💡 핵심 요약 (TL;DR)
Exceprion이 발생했을 때 어떤 부분의 예외인지 그 이름을 알고 싶을때 Exception클래스 내 e.getClass().getName()메서드를 사용할 수 있다.
* @ControllerAdvice: 글로벌 예외처리을 통해 문제를 해결할 수 있다.
예외처리 어노테이션
@ControllerAdvice: 글로벌 예외처리
@ControllerAdvice(특정패키지명): 괄호안에 특정 package명을 기재하면 해당 package만 예외처리함
- @ControllerAdvice(“com.test.springeprjt”): excom.test.springeprjt를 라는 특정 package 예외처리
@ExceptionHandler: 특정 controller예외처리
Exceprion이 발생했을 때 어떤 부분의 예외인지 그 이름을 알고 싶을때 Exception클래스 내 e.getClass().getName()메서드를 사용할 수 있다.
다른 개발자가 봐도 알기쉽도록 메시지를 꾸며보자
- ErrorResponse.java
한 파라미터에 조건이 여러 개가 있을 수 있으므로 List로 에러필드와 에러메시지를 받을 필요가 있다.
1 2 3 4 5 6 7 8 9 10
| @Data public class ErrorResponse { String statusCode; String requestUrl; String code; String message; String resultCode;
List<Error> errorList; }
|
1 2 3 4 5 6
| @Data public class Error { private String field; private String message; private String invalidValue; }
|
이제 제일 중요한 컨트롤러 부분을 보자.
- ApiControllerAdvice.java
String으로 각각 에러값을 받은 다음 위에서 선언한 Error클래스에 set해준 뒤 list에 add해준다.
각 예외클래스마다 사용할 수 있는 것들이 다르니 디버그나 공식문서를 통해서 원하는 내용을 찾으면 된다!
아래 예시는 가장 기본이 되는 방식
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| @RestControllerAdvice(basePackageClasses = ApiController.class) public class ApiControllerAdvice { @ExceptionHandler(value = MethodArgumentNotValidException.class) public ResponseEntity methodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest httpServletRequest){
List<Error> errorList = new ArrayList<>();
BindingResult bindingResult = e.getBindingResult(); bindingResult.getAllErrors().forEach(error -> { FieldError field = (FieldError) error;
String fieldName = field.getField(); String message = field.getDefaultMessage(); String value = field.getRejectedValue().toString(); Error errorMessage = new Error(); errorMessage.setField(fieldName); errorMessage.setMessage(message); errorMessage.setInvalidValue(value);
errorList.add(errorMessage); });
ErrorResponse errorResponse = new ErrorResponse(); errorResponse.setErrorList(errorList); errorResponse.setMessage(""); errorResponse.setRequestUrl(httpServletRequest.getRequestURI()); errorResponse.setStatusCode(HttpStatus.BAD_REQUEST.toString()); errorResponse.setResultCode("FAIL");
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse); }
@ExceptionHandler(value = ConstraintViolationException.class) public ResponseEntity constraintViolationException(ConstraintViolationException e, HttpServletRequest httpServletRequest){
List<Error> errorList = new ArrayList<>();
e.getConstraintViolations().forEach(error ->{ Stream<Path.Node> stream = StreamSupport.stream(error.getPropertyPath().spliterator(), false); List<Path.Node> list = stream.collect(Collectors.toList());
String field = list.get(list.size() -1).getName(); String message = error.getMessage(); String invalidValue = error.getInvalidValue().toString();
Error errorMessage = new Error(); errorMessage.setField(field); errorMessage.setMessage(message); errorMessage.setInvalidValue(invalidValue);
errorList.add(errorMessage);
});
ErrorResponse errorResponse = new ErrorResponse(); errorResponse.setErrorList(errorList); errorResponse.setMessage(""); errorResponse.setRequestUrl(httpServletRequest.getRequestURI()); errorResponse.setStatusCode(HttpStatus.BAD_REQUEST.toString()); errorResponse.setResultCode("FAIL");
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse); }
@ExceptionHandler(value = MissingServletRequestParameterException.class) public ResponseEntity missingServletRequestParameterException(MissingServletRequestParameterException e, HttpServletRequest httpServletRequest){
List<Error> errorList = new ArrayList<>();
String fieldName = e.getParameterName(); String invalidValue = e.getMessage();
Error errorMessage = new Error(); errorMessage.setField(fieldName); errorMessage.setMessage(e.getMessage());
ErrorResponse errorResponse = new ErrorResponse(); errorResponse.setErrorList(errorList); errorResponse.setMessage(""); errorResponse.setRequestUrl(httpServletRequest.getRequestURI()); errorResponse.setStatusCode(HttpStatus.BAD_REQUEST.toString()); errorResponse.setResultCode("FAIL");
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse); } }
|
결과
만약 valid 설정을 아래와 같이 했다면 예외 메시지는 어떻게 나올까?
1 2 3 4 5 6 7 8 9
| @Data public class User {
@NotEmpty @Size(min=1, max=10) private String name; @Min(1) @NotNull private Integer age; }
|
1 2 3 4 5 6 7 8 9 10 11
| @RestController @RequestMapping("/api/user") @Validated public class ApiController { @PostMapping("") public User post(@Valid @RequestBody User user) { System.out.println("@ post call"); return user; } }
|
위처럼 유효성체크를 설정한 뒤 POST맨을 통한 결과를 알아보자.
name에 빈값을 넣었고, age에는 0을 넣었다.

사진처럼 다른 개발자가 보아도 이해하기 쉬운 에러메시지를 확인할 수 있다.
출처
#패스트캠퍼스(초격차Java/Spring)