[TIL] 개인 프로젝트 - '일정 관리 프로젝트' 후기
1. 일정 관리 프로젝트
이번에는 Spring
을 이용한 첫 프로젝트입니다
여러가지 어노테이션을 사용하면서 예외 처리도 더욱 다양해지니 난이도가 훨씬 증가한 느낌이 드네요
이번 프로젝트에서 배운 내용도 한 번 정리해보도록 하겠습니다
- 완성된 프로젝트는 Sparta-Quest-Schedule-App에서 확인할 수 있습니다
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. 스프링에서 예외 처리하기
클라이언트가 어떻게 보낼지 모르는 상황에서 컨트롤러는 다양한 예외 처리를 전달해줘야 합니다
그런데 경우의 수가 많아질 수록 컨트롤러가 복잡해지지 않을까요
새로운 예외 추가
비밀번호가 안맞는다던가, 일정을 찾을 수 없다던가 하는 예외도 따로 추가해주기 위해
public class SchedueNotFoundException extends RuntimeException
처럼 예외 클래스를 만들었습니다처음에는 서비스에서 throw한 Exception을 컨트롤러가 잡아서(try-catch) 처리
HttpStatus.NOT_FOUND
,HttpStatus.UNAUTHORIZED
같은걸 붙인 ResponseEntity를 반환하도록 말이죠
여기까지는 어렵지 않았지만 점차 유지보수가 매우 어려워질 것 같은 느낌이 들어서 새로운 방법을 모색해봤습니다예외를 처리하는
GlobalExceptionHandler
와 각 예외 정보를 담아줄ErrorResponseDto
클래스 생성
[Commit - 14015ba]@RestControllerAdvice, @ExceptionHandler
어노테이션을 통해GlobalExceptionHandler
에서 예외를 잡아내
상태 코드와 메시지를 담은ResponseEntity
를 반환해주니 유지보수가 훨씬 간단해지게 되었습니다다양한 예외에 대한 상태 코드와 메시지를
Enum
에 저장
[Commit - 9d25d99]새로운 예외가 많아지면 그만큼 클래스를 늘려야 하는걸까..싶었지만
Enum
으로 처리해주면 훨씬 쉽지 않을까요
그래서 기존 새로운 예외 클래스는 지우고Enum
으로 처리해보니… 더 간단해질 수 있다는게 놀라웠습니다
- 정리 // <클래스명>은 직접 작명하시면 됩니다 클래스명>
Service
에서 예외를 던지고<CustomException> extends RuntimeException
에enum <ErrorCode>
의 값을 선택해서throw
<GlobalExceptionHandler>
에서 해당 예외를 잡아낸 뒤ResponseEntity
로 반환
겨우 이 정도만 했을 뿐인데 컨트롤러에서 try-catch를 작성하고 하나씩 예외를 잡아 처리해 줄 필요가 없어졌습니다
앞으로는 enum ErrorCode
에 새로운 예외를 추가하고 throw
만 하면 되니까 말이죠
4. Entity <-> Dto
Repository
가 조회한 값을 Service
로 Entity
를 전달하면, 이후 Controller
에는 DTO
를 전달해야 합니다
그러면 Service
에서 Entity
와 DTO
를 서로 변환해주는 코드를 작성해줘야 되는 것이 아닐까요
4-1. 문제가 생긴 부분
막상 Service
에서 EntityToDto
메서드를 만들어서 사용해봤는데.. 잘 사용하다가 문제가 생기더라구요
일정을 반환하는 방법이 2가지가 있습니다
- 일정 내용만 반환
- 일대다 관계의 댓글까지 함께 반환
일정 서비스에서 댓글까지 반환하기 위해서는 댓글도 Dto로 변환해서 넣어줘야 합니다
그러면 일정 서비스는 댓글 서비스를 담아야하는데.. 댓글 서비스가 이미 일정 서비스를 담고 있었습니다
즉, 두 서비스가 서로의 서비스를 @RequiredArgsConstructor
로 주입하니 엉켜서 에러가 발생하게 됩니다
4-2. 해결한 방법
Dto
와 Entity
를 서로 변환해주는 메서드를 서비스가 아닌 저장소 계층에 넣어줬습니다
스샷처럼 작성하니 일정과 댓글을 같이 반환해주기가 매우 편해지더라구요
…사실 시간이 부족하여 Dto <-> Entity
의 변환을 자세히 찾아보지 못했는데 ModelMapper
도 있고
서비스 또는 저장소 계층에서 변환했을 때의 장단점이 각각 있었습니다
이미 프로젝트는 마무리 되었으니 한 번 찾아봐야겠습니다
5. 여담
사실 기본적인 스프링 내용을 거의 다 잊었기 때문에 새로 학습하는 데에만 이틀을 소요했습니다
게다가 이번 TIL에 작성한 것 처럼 스프링의 예외 처리, DTO - Entity 변환 내용도 새롭게 배웠구요
그래서 시간이 다소 부족한 상태로 마무리가 되어 깔끔하게 확인해보지 못한 것이 아쉬웠습니다
하지만 늘 새로운 내용을 배운다는 것은 재밌기 때문에 이번에도 매우 유용한 경험이 되었습니다
다음 프로젝트도 내일 바로 시작될 예정인 것 같은데 오늘 배운 내용을 깔끔하게 써먹을 수 있으면 좋겠네요