예외처리 어노테이션
@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 설정을 아래와 같이 했다면 예외 메시지는 어떻게 나올까?
User.java
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; }
ApiController.java
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을 넣었다.
사진처럼 다른 개발자가 보아도 이해하기 쉬운 에러메시지를 확인할 수 있다.
출처