Post

[TIL] 개인 프로젝트 - '일정 관리 프로젝트' 후기

[TIL] 개인 프로젝트 - '일정 관리 프로젝트' 후기

1. 일정 관리 프로젝트

이번에는 Spring을 이용한 첫 프로젝트입니다
여러가지 어노테이션을 사용하면서 예외 처리도 더욱 다양해지니 난이도가 훨씬 증가한 느낌이 드네요

이번 프로젝트에서 배운 내용도 한 번 정리해보도록 하겠습니다



2. 어노테이션 (Annotation)

스프링 어노테이션은 애플리케이션에서 필요로 하는 다양한 기능을 부여해주는 역할을 합니다

1
2
3
4
5
6
7
8
9
@Getter
@Setter
public class User {
    private String name;
    private int age;

    // @Getter -> .getName(), .getAge()가 자동으로 추가 됨
    // @Setter -> .setName(), .setAge()가 자동으로 추가 됨
}

예를 들면 위처럼 Getter, Setter같은 기능을 사용하기 위해 길게 코드를 작성할 필요가 없이
단지 어노테이션 한두개 추가하면서 사용할 수 있게 되는 것이라 볼 수 있겠습니다

다만, @Setter은 해당 객체를 변경할 수 있는 어노테이션이니 사용에 주의가 필요합니다

어노테이션의 종류가 매우 다양한데, 대부분 이해하기 쉬운 것들이 많으니 한 번 찾아보고 사용해보면 됩니다

  • @AllArgsCostructor, @NoArgsConstructor : 생성자 어노테이션
  • @Service, @Entity, @Controller : 3Layer Archiecture 관련 어노테이션
  • @RequiredArgsConstructor : final 필드나 @NonNull이 붙은 필드에 의존성 주입


3. 스프링에서 예외 처리하기

img

클라이언트가 어떻게 보낼지 모르는 상황에서 컨트롤러는 다양한 예외 처리를 전달해줘야 합니다
그런데 경우의 수가 많아질 수록 컨트롤러가 복잡해지지 않을까요

  1. 새로운 예외 추가

    비밀번호가 안맞는다던가, 일정을 찾을 수 없다던가 하는 예외도 따로 추가해주기 위해
    public class SchedueNotFoundException extends RuntimeException처럼 예외 클래스를 만들었습니다

  2. 처음에는 서비스에서 throw한 Exception을 컨트롤러가 잡아서(try-catch) 처리

    HttpStatus.NOT_FOUND, HttpStatus.UNAUTHORIZED같은걸 붙인 ResponseEntity를 반환하도록 말이죠
    여기까지는 어렵지 않았지만 점차 유지보수가 매우 어려워질 것 같은 느낌이 들어서 새로운 방법을 모색해봤습니다

  3. 예외를 처리하는 GlobalExceptionHandler와 각 예외 정보를 담아줄 ErrorResponseDto 클래스 생성
    [Commit - 14015ba]

    @RestControllerAdvice, @ExceptionHandler 어노테이션을 통해 GlobalExceptionHandler에서 예외를 잡아내
    상태 코드와 메시지를 담은 ResponseEntity를 반환해주니 유지보수가 훨씬 간단해지게 되었습니다

  4. 다양한 예외에 대한 상태 코드와 메시지를 Enum에 저장
    [Commit - 9d25d99]

    새로운 예외가 많아지면 그만큼 클래스를 늘려야 하는걸까..싶었지만 Enum으로 처리해주면 훨씬 쉽지 않을까요
    그래서 기존 새로운 예외 클래스는 지우고 Enum으로 처리해보니… 더 간단해질 수 있다는게 놀라웠습니다

  • 정리 // <클래스명>은 직접 작명하시면 됩니다
    • Service에서 예외를 던지고
      <CustomException> extends RuntimeExceptionenum <ErrorCode>의 값을 선택해서 throw
    • <GlobalExceptionHandler>에서 해당 예외를 잡아낸 뒤 ResponseEntity로 반환

겨우 이 정도만 했을 뿐인데 컨트롤러에서 try-catch를 작성하고 하나씩 예외를 잡아 처리해 줄 필요가 없어졌습니다
앞으로는 enum ErrorCode에 새로운 예외를 추가하고 throw만 하면 되니까 말이죠



4. Entity <-> Dto

img

Repository가 조회한 값을 ServiceEntity를 전달하면, 이후 Controller에는 DTO를 전달해야 합니다
그러면 Service에서 EntityDTO를 서로 변환해주는 코드를 작성해줘야 되는 것이 아닐까요

4-1. 문제가 생긴 부분

막상 Service에서 EntityToDto 메서드를 만들어서 사용해봤는데.. 잘 사용하다가 문제가 생기더라구요

일정을 반환하는 방법이 2가지가 있습니다

  • 일정 내용만 반환
  • 일대다 관계의 댓글까지 함께 반환

일정 서비스에서 댓글까지 반환하기 위해서는 댓글도 Dto로 변환해서 넣어줘야 합니다
그러면 일정 서비스는 댓글 서비스를 담아야하는데.. 댓글 서비스가 이미 일정 서비스를 담고 있었습니다

즉, 두 서비스가 서로의 서비스를 @RequiredArgsConstructor로 주입하니 엉켜서 에러가 발생하게 됩니다

4-2. 해결한 방법

img DtoEntity를 서로 변환해주는 메서드를 서비스가 아닌 저장소 계층에 넣어줬습니다
스샷처럼 작성하니 일정과 댓글을 같이 반환해주기가 매우 편해지더라구요

…사실 시간이 부족하여 Dto <-> Entity의 변환을 자세히 찾아보지 못했는데 ModelMapper도 있고
서비스 또는 저장소 계층에서 변환했을 때의 장단점이 각각 있었습니다
이미 프로젝트는 마무리 되었으니 한 번 찾아봐야겠습니다


5. 여담

사실 기본적인 스프링 내용을 거의 다 잊었기 때문에 새로 학습하는 데에만 이틀을 소요했습니다
게다가 이번 TIL에 작성한 것 처럼 스프링의 예외 처리, DTO - Entity 변환 내용도 새롭게 배웠구요

그래서 시간이 다소 부족한 상태로 마무리가 되어 깔끔하게 확인해보지 못한 것이 아쉬웠습니다
하지만 늘 새로운 내용을 배운다는 것은 재밌기 때문에 이번에도 매우 유용한 경험이 되었습니다

다음 프로젝트도 내일 바로 시작될 예정인 것 같은데 오늘 배운 내용을 깔끔하게 써먹을 수 있으면 좋겠네요

This post is licensed under CC BY 4.0 by the author.