심화주차 과제의 마무리였다. 어제까지 만든 기능들에 Exception으로 예외처리를 해줬다.
GlobalExceptionHandler를 이용해 한곳에서 모든 에러들을 핸들링 할 수 있었다.
- 동일한 에러들을 마크할 수 있어 생산성이 올라가고,
- 한곳에서 에러들을 모두 관리할 수 있어 관리하기도 수훨했다.
사용방법은 @RestControllerAdvice를 이용하는 방법이다.
@RestControllerAdvice : @ExceptionHandler, @ModelAttribute, @InitBinder 가 적용된 메서드들에 AOP를 적용해 Controller 단에 적용하기 위해 고안된 어노테이션이며, ResponseBody도 같이 적용되어있어 객체를 리턴해줄 수 도 있다.
ExceptionHandler들을 컨트롤할 클래스를 하나 만들고 내부에 @ExceptionHandler어노테이션을 적용한 ExceptionHandler들을 작성해 필요할 때 필요한 Handler를 꺼내 사용할 수 있다.
아래는 예시로 2가지만 ExceptionHandler를 만들어둔 모습이다.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler({AccountOfTheWrongRules.class}) //회원가입시 중복된 사용자 존재
public ResponseEntity<ApiResponseDto> handleException(AccountOfTheWrongRules ex) {
ApiResponseDto apiResponseDto = new ApiResponseDto(ex.getMessage(), HttpStatus.BAD_REQUEST.value());
return new ResponseEntity<>(
// HTTP body
apiResponseDto,
// HTTP status code
HttpStatus.BAD_REQUEST
);
}
@ExceptionHandler({NotHavePermission.class}) //수정삭제 권한이 존재하지 않을 때
public ResponseEntity<ApiResponseDto> handleException(NotHavePermission ex) {
ApiResponseDto apiResponseDto = new ApiResponseDto(ex.getMessage(), HttpStatus.FORBIDDEN.value());
return new ResponseEntity<>(
// HTTP body
apiResponseDto,
// HTTP status code
HttpStatus.FORBIDDEN
);
}
}
apiResponseDto는 내가 임의로 만든 String과 Integer형을 가진 클래스이다. 에러메세지와 HttpCode를 반환하기 위해 만들었다.
ExceptionHandler클래스 내부
public class NotHavePermission extends RuntimeException { //권한이 없을 때
public NotHavePermission(String msg) {
super(msg);
}
}
그렇다면 저 ExceptionHandler들을 꺼내 쓸 땐 어떻게 써야할까?
아래 코드는 게시글 삭제시 현재 접속한 유저가 게시글을 작성한 유저가 아닐 때, 삭제가 불가하게 권한이 없다는걸 ExceptionHandler를 이용해 표시했다.
throw new NotHavePermission(messageSource.getMessage( //권한이 없을 때
"not.have.permission",
null,
"You Do Not Have Permission",
Locale.getDefault()
));
위 코드를 보면 not.hav.permission이 보일텐데, 해당 이름은 properties로 미리 설정해둔 String메세지가 출력되게 된다.
나는 messages.properties를 만들어 미리 메세지 값을 설정해뒀다.
해당 작업 프로젝트 git 주소 : https://github.com/skah1061/8Week