내일배움캠프/TIL

[Spring_4기 본캠프] 메모장 실습과 Postman, 깃모지 | Day 35

austindynasty 2024. 12. 4. 16:16

1. 실습을 활용해 일정관리 앱으로 둔갑시키기

  인프런 강의만 듣다가는 과제를 끝내지 못할 것같아 캠프에서 지급해준 강의에 나온 메모장 만들기 실습을 바로 진행하기로 했다.

메모장이나 일정관리 앱이나, 이름만 다르지 거기서 거기 아닌가? 라는 생각이 들어 Memo를 Todo로 바꾸며 프로그램을 작성했다.

↓ 1차 완성 코드 ( CRUD 기능만 있음 ) ↓

더보기
package com.example.todo.entity;

import com.example.todo.dto.ToDoRequestDto;
import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 일정 관리 애플리케이션의 ToDo Entity 클래스
 * 이 클래스는 데이터베이스의 ToDo 테이블과 매핑되며 일정 데이터를 표현한다.
 *
 * <p>
 * - id : 일정의 고유 식별자
 * - title : 일정의 제목
 * - contents : 일정의 내용
 * </p>
 *
 * Lombok 애너테이션
 * - @Getter : 모든 필드에 대한 Getter 메서드를 자동 생성
 * - @AllArgsConstructor : 모든 필드를 초기화하는 생성자를 자동 생성
 */

@Getter
@AllArgsConstructor
public class ToDo {
    private Long id;
    private String title;
    private String contents;

    public void update(ToDoRequestDto requestDto) {
        title = requestDto.getTitle();
        contents = requestDto.getContents();
    }
}
package com.example.todo.dto;

import lombok.Getter;

/**
 * 일정 관리 애플리케이션의 ToDoRequestDto 클래스
 * <p>
 *  클라이언트로부터 전달받은 데이터를 담는 DTO
 *  새로운 일정 생성 요청이나 기존 일정 수정 시 사용
 *
 *  - title : 일정의 제목으로 클라이언트가 요청한 일정의 이름
 *  - contents : 클라이언트가 요청한 일정에 대한 구체적인 내용
 * </p>
 *
 * Lombok 애너테이션
 * - @Getter : 모든 필드에 대한 Getter 메서드를 자동 생성
 */

@Getter
public class ToDoRequestDto {
    private String title;
    private String contents;
}
package com.example.todo.dto;

import com.example.todo.entity.ToDo;
import lombok.Getter;

/**
 * 클라이언트에게 데이터를 반환할 때 사용하는 ToDoResponseDto 클래스
 * 일정 조회, 생성 완료 응답, 수정 완료 응답 시 사용
 * <p>
 * - id : 일정의 고유 식별자를 반환
 * - title : 일정의 제목을 반환
 * - contents : 일정의 내용을 반환
 * </p>
 *
 * Lombok 애너테이션
 *- @Getter : 모든 필드에 대한 Getter 메서드를 자동 생성
 */
@Getter
public class ToDoResponseDto {
    private Long id;
    private String title;
    private String contents;

    public ToDoResponseDto(ToDo todo) { // 매개변수로 Todo 객체를 그대로 받음
        id = todo.getId();
        title = todo.getTitle();
        contents = todo.getContents();
    }
}
package com.example.todo.controller;

import com.example.todo.dto.ToDoRequestDto;
import com.example.todo.dto.ToDoResponseDto;
import com.example.todo.entity.ToDo;
import org.springframework.web.bind.annotation.*;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 일정 관리 애플리케이션의 ToDoController 클래스
 * 일정 관리와 관련된 HTTP 요청을 처리
 *
 * /todos 엔드포인트를 통해 클라이언트와 통신
 * Map 자료구조를 In-memory 데이터베이스로 사용하여 일정 데이터 저장 ( 임시 활용 )
 */

@RestController // 데이터의 형태를 JSON으로 일일이 바꿔주지 않아도 RestController 에서 자동으로 JSON 형태로 반환해주기 때문에
@RequestMapping("/todos") // 공통으로 들어가는 /todos url
public class ToDoController {
    // 자료구조 Map을 임시 데이터베이스로 사용
    private final Map<Long, ToDo> todoList = new HashMap<>();

    // 일정 생성 기능
    @PostMapping
    public ToDoResponseDto createTodo(@RequestBody ToDoRequestDto requestDto) { //createTodo() : 클라이언트로부터 전달받은 데이터를 기반으로 새 일정을 생성하고 생성된 데이터를 클라이언트에 반환
        // 중복이 되지 않도록 식별자가 1씩 증가하도록 만든다.
        Long todoId = todoList.isEmpty() ? 1 : Collections.max(todoList.keySet()) + 1;

        // 요청받은 데이터로 Todo 객체 생성
        ToDo todo = new ToDo(todoId, requestDto.getTitle(), requestDto.getContents());

        // In-memory DB에 Todo 일정 저장 : 실제 데이터베이스를 연결하지 않고 Map 자료구조를 사용함 -> 프로젝트가 실행되었다가 종료될 때 모든 메모리가 삭제됨
        todoList.put(todoId, todo);

        return new ToDoResponseDto(todo); // 매개변수로 받은 todo 객체를 ResponseDto 형태로 반환
    }

    // 일정 조회 기능
    @GetMapping("/{id}") // prefix 로 todos가 만들어져 있기 때문에 식별자를 입력해준다. 식별자를 파라미터로 바인딩 할 때 Pathvariable을 이용한다.
    public ToDoResponseDto findTodoById(@PathVariable Long id) {
       ToDo toDo = todoList.get(id);

        return new ToDoResponseDto(toDo);
    }

    //일정 수정 기능
    @PutMapping("/{id}")
    public ToDoResponseDto updateTodoById(
            @PathVariable Long id,
            @RequestBody ToDoRequestDto requestDto
    ) {
        ToDo todo = todoList.get(id);

        todo.update(requestDto);

        return new ToDoResponseDto(todo);
    }

    //일정 삭제 기능
    @DeleteMapping("/{id}")
    public void deleteTodo(@PathVariable Long id) {
        todoList.remove(id);
    }
}

 

  일정을 생성하고, 조회하고, 수정하고, 삭제하는 간단한 CRUD 기능을 하는 일정관리 프로그램을 작성했다.

아직 특정 날짜에 일정을 등록하거나 수정한 날짜가 나오진 않지만 기본적인 틀은 갖춘 것이다.

DTO가 무엇이고, 각각의 애너테이션이 어떠한 역할을 하는지 공부를 하고 실습을 진행한 것이 아니지만 코드를 작성해보고나니 어떠한 역할을 하는 지는 대충 감이 잡혀 개념공부를 할 때 조금 수월할 것이라는 기대를 하고있다.

 

이제 내가 실습을 진행하면서 발생했던 문제와 해결과정을 정리하고자 한다.

 

< 문제 > 일정 단건 조회 API 실행 시 500 Internal Server Error 발생

  일정 단건 조회 기능을 추가한 후에 GET /todos/{id} API를 Postman을 이용해 호출한 결과 500 Internal Server Err가 발생했다. 

인텔리제이 콘솔 창에도 에러가 발생해 내용을 읽어보니 todo is null 이라며 todo 가 비어 NullPointerException이 발생했다는 얘기같았다.

하지만 난 분명 아까 데이터를 추가했는데 왜 비었다고하지? 라는 생각이 들었다.

  현재 실습에서는 아직 데이터 서버를 지정하지 않아 임시로 자료구조 Map를 데이터 저장소로 활용하고 있었다. 

Map를 데이터 저장소로 이용할 경우 프로그램이 실행되었다가 종료되면 저장된 데이터가 모두 삭제된다는 것이 떠올랐다.

그래서 GET /todos/{id} 로 조회 기능을 사용하기 전에 POST /todos API를 호출해 데이터를 새로 저장했다.

이후 GET /todos/1 API를 호출하니 아래 사진과 같이 결과가 정상적으로 출력됐다.

  < 정리 >

문제 : 일정 단건 조회 기능의 테스트를 위해 Postman 을 사용, GET /todos/{id} API 호출 시 500 Internal Server Error 발생함

원인 : 데이터 저장소로 임시 자료구조 Map을 사용하고 있어 프로그램 실행 후 종료 시 데이터가 초기화 되어 Null이 요청됨

해결 : POST /todos API를 호출해 데이터를 새로 저장한 후 GET /todos/{id} API 를 재호출해 정상 작동하는 것을 확인함

 

2. Postman

  이번 실습에서는 사용자에게 보여지는 화면이 따로 없기 때문에 내가 개발한 API가 정상 작동하는지 확인할 수가 없었다.

그래서 Postman이라는 프로그램을 사용해 API가 반환하는 결과값을 확인했다.

 

정상작동 되었을 때는 JSON 형태의 데이터가 반환되는 것을 볼 수 있고, 문제가 발생했을 때에는 위 그림처럼 에러가 난 시각과 에러코드, 에러 내용과 경로가 보여진다. 

 

 

3. 깃모지 사용기

  직전에 실습을 진행할 때 깃을 잘 활용하지 못했던 것이 아쉬운 점으로 남았어서 이번에 새롭게 실습을 진행하면서는 기능 하나를 추가한 후 정상 작동하는 지 확인하고 깃 푸쉬를 했다. 푸쉬를 하기 전에는 꼭 add 와 commit을 해야하는데 깃허브에서 커밋 기록을 읽어보니 가독성이 떨어진다는 생각이 들었다. 보자마자 어떤 사항으로 커밋을 하는지 알았으면 좋겠다! 라고 느껴 찾아보던 중 현업에서 깃모지를 많이들 활용한다는 글을 보았다. ( 참고 사이트 : https://gitmoji.dev/ )

  깃 커밋 메시지를 작성할 때 한글로 쓰면 더 좋지만 한글로 쓸 때 자꾸 딜레이되는 것이 싫고, 영어공부도 할 겸 영어로 작성하고 있다. 

(문법 상 틀린 점과 컨벤션에 맞지 않다면 많은 지적 감사..) 아직 나만 보는 커밋 기록이니까, 간단하고 쉬운 단어들로만 메시지를 작성했다.

인텔리제이에서 깃모지 플러스 플러그인을 다운받아 사용해봤는데 확실히 어떤 깃모지가 어떤 사항을 의미하는지 정하고나면 커밋 기록을 봤을 때 편할 것같다는 생각이 들었다.

 

 

4. 실습 진행 시 필요했던 개념 정리

 

* 3 계층 아키텍쳐와 3 레이어 아키텍쳐 

특징 3 레이어 아키텍쳐 3 계층 아키텍쳐
구분 방식 논리적으로 구분 (코드 구조) 물리적으로 구분 (서버 구조)
초점 애플리케이션 내부의 역할 분리 시스템 전반의 계층적 분리
운영 환경 같은 서버에서 동작 각 계층이 서로 다른 서버에서 동작 가능
유형 개발자 관점의 소프트웨어 설계 시스템 관점의 네트워크 설계
예시 한 서버에서 Service, DAO, UI 를 분리 클라이언트, API 서버, DB 서버로 분리

 

 

쓰다보니 너무 길어져 글을 따로 뺐다.. 참고하실 분들은 아래 링크 방문! 

https://austindynasty.tistory.com/47

 

3 계층 아키텍쳐 (3-tier-architecture) VS 3 레이어 아키텍쳐(3-layer-architecture)

◆ 3계층 아키텍쳐 ( 3-tier-architecture ): 프레젠테이션 계층 (사용자 인터페이스) / 데이터가 처리되는 애플리케이션 계층 / 데이터가 저장 및 관리되는 데이터 계층 이라는 3개의 논리적이고

austindynasty.tistory.com