어렴풋이 알았었다. 핸들러의 존재.
하지만 활용은 못했었다.
하지만 이번 과제를 계기로 핸들러의 존재를 알게 되었다.
그럼 뭐다? 활용한다!
아맞다 과제 회사는 떨어짐...ㅋ굿 ㅋㅋ
try {
String tagJson = tagService.writeForMain(id, tagDto);
jsonObject.addProperty("tag", tagJson);
} catch (UserNotFoundException e) {
log.error("헤더에 들어있는 id 가 진짜 id 가 아니었다 Id = {}", id);
jsonObject.addProperty("response", Response.USER_NOT_FOUND);
return webService.badResponse(jsonObject);
}
내 컨트롤러에는 이런 무분별한 try-catch 문들이 많았다.
이건 컨트롤러에서 직접 예외를 잡는 방법이다.
하지만 예외가 생길 경우!
이렇게 컨트롤러에서까지도 예외를 던져주면
핸들러에게 예외를 잡는 행위를 온전히 위임할 수 있다는 사실 ! (듀듕!)
핸들러를 만드는 법은 간단하당.
@ControllerAdvice
public class UserExceptionHandler {
핸들러 역할을 할 클래스에 @ControllerAdvice 애노테이션을 붙여준 후
@ExceptionHandler(UserNotFoundException.class)
메서드 위에는 @ExceptionHandler 로 어떤 예외를 잡는가 표시해주고
public ResponseEntity<Response> userNotFoundHandler(UserNotFoundException e) {
해당 메서드 매개변수로 해당 예외를 잡아주고
return Response.badRequest(e.getMessage());
응답을 해준다.
@ControllerAdvice
public class UserExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<Response> userNotFoundHandler(UserNotFoundException e) {
return Response.badRequest(e.getMessage());
}
@ExceptionHandler(UsernameDuplException.class)
public ResponseEntity<Response> usernameDuplicateHandler(UsernameDuplException e) {
return Response.badRequest(e.getMessage());
}
@ExceptionHandler(LoginException.class)
public ResponseEntity<Response> loginExceptionHandler(LoginException e) {
return Response.badRequest(e.getMessage());
}
}
그러면 요런 형식의 핸들러가 만들어진다!!!ㅎ_ㅎ
나는 e.getMessage() 를 넣어, 해당 예외가 발생했을 때 내가 넣은 예외 메시지를 응답 객체에 넣어주었당.ㅎㅎㅎ
그러면 프론트에서 좀 더 쉽게 예외 이유를 알 수 있겠지요? ㅎㅎㅎㅎㅎ 헷
응답 형식도 좀 변경했다.
Response 객체를 따로 만들었다.
public class Response {
String message;
HttpStatus status;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
LocalDateTime timestamp;
Object data;
public static ResponseEntity<Response> ok(String message, Object data) {
return responseWithData(HttpStatus.OK, message, data);
}
public static ResponseEntity<Response> ok() {
return response(HttpStatus.OK, "SUCCESS");
}
public static ResponseEntity<Response> ok(Object data) {
return responseWithData(HttpStatus.OK, "SUCCESS", data);
}
public static ResponseEntity<Response> badRequestWithData(String message, Object data) {
return responseWithData(HttpStatus.BAD_REQUEST, message, data);
}
public static ResponseEntity<Response> badRequest(String message) {
return response(HttpStatus.BAD_REQUEST, message);
}
private static ResponseEntity<Response> responseWithData(HttpStatus status, String message, Object data) {
return ResponseEntity.status(status).body(
Response.builder()
.status(status)
.message(message)
.timestamp(LocalDateTime.now())
.data(data)
.build()
);
}
private static ResponseEntity<Response> response(HttpStatus status, String message) {
return ResponseEntity.status(status).body(
Response.builder()
.status(status)
.message(message)
.timestamp(LocalDateTime.now())
.build()
);
}
}
ResponseEntity<Response> 형식으로 응답한다.
응답은
메시지, 스테이터스코드, 타임스탬프(응답시간), 데이터(있다면 같이 보내기) 를 보낼 수 있다.
데이터를 같이 보내는 응답을 보며 확인해보자.
private static ResponseEntity<Response> responseWithData(HttpStatus status, String message, Object data) {
return ResponseEntity.status(status).body(
Response.builder()
.status(status)
.message(message)
.timestamp(LocalDateTime.now())
.data(data)
.build()
);
}
ResponseEntity 를 보내되, 바디에 Response 형식이 들어가는 리턴이다.
그래서 바디에 Response 를 빌딩하는 코드를 써넣고
스테이터스, 메시지, 타임스탬프, 데이터를 함께 넣어주었다.
ResponseEntity 바디 안에 Response 객체를 써넣고 응답해주면 된다.
public static ResponseEntity<Response> ok(Object data) {
return responseWithData(HttpStatus.OK, "SUCCESS", data);
}
다른 클래스들이 직접 사용하는 ok 응답 객체다.
성공했다면 메시지는 간단하게 SUCCESS 로 주고, OK도 기본이고, 데이터만 주어진 걸 넣는다.
그리고 응답 객체는 모든 컨트롤러가 사용하므로
인스턴스를 만들지 않고도 사용할 수 있도록
편하게 스태틱 메서드로 만든당!~
그러면 결론은...원본 컨트롤러에서는?
@GetMapping
public ResponseEntity<Response> list(HttpServletRequest request) throws UserNotFoundException {
Long id = webService.getIdInHeader(request);
List<String> tagList = tagService.tagList(id);
String tagListJson = webService.objectToJson(tagList);
return Response.ok(tagListJson);
}
이렇게 간단한 코드가 만들어지는 것이다.
try-catch 문이 없어지고 예외를 던지기만 하면 간단하게 모든 처리가 가능하다!
이렇게 핸들러와 응답용 객체를 사용해서 아쥬아쥬 편리하게 컨트롤러 리팩토링 완료!!!!
-> 사실 tagList 를 직접 응답 객체에 넣어서 사용해도 된다.
하지만 ... 프론트에서 이미 tagList { 리스트 내역 } 형식으로 받기 때문에
부득이하게 제이슨으로 변환하여 사용할 수 밖에 없다는 구슬픈 사실 ㅠㅠ
이래서 처음부터 설계를 잘 하라는 건가보당...
해당 리팩토링 관련 커밋은 이곳에서 확인 가능하답니당!^_^
https://github.com/h0l1da2/MEMO-RE_BE/commit/d4c5db3f4d1e3f2af18e88a1e47ca470142e0c7f
refactor: Exception try-catch -> Handler 로 바꿈 · h0l1da2/MEMO-RE_BE@d4c5db3
핸들러에서 예외 잡는 것으로 변경
github.com
'프로젝트 > 팀 프로젝트) MEMO:RE' 카테고리의 다른 글
Test ) 간단한 단위 테스트 추가 (0) | 2024.02.22 |
---|---|
MEMO:RE ) 팀 프로젝트 후기 (1) | 2023.08.14 |
9~10일차 ) 안 되면 밤새면 되지 (0) | 2023.08.14 |
8일차 ) 그래서 니가 뭘 할 수 있는데? (0) | 2023.08.10 |
7일차 ) Rest Api 비켜 ! 프론트 통신 성공 ! (0) | 2023.08.09 |