bindingResult : 스프링이 제공하는 검증 오류 보관 객체. 검증 오류가 발생하면 BindingResult 객체에 보관.
- @ModelAttribute 바로 옆에 둬야 한다.
ObjectError : 글로벌 오류.
FieldError : 필드 오류. FieldError(검증 객체 이름, 오류가 발생한 필드 이름, 오류 기본 메시지)
- 타입 오류로 바인딩에 실패하면 FieldError 를 생성하며 오류를 넣고, 해당 오류를 BindinResult 에 담아 컨트롤러를 호출.
@RestControllerAdvice
- 여러 개의 Controller 클래스에서 @ExceptionHandler 가 추가된 메서드를 공유해 사용할 수 있다.
- 이 에너테이션을 추가한 클래스를 통해 예외 처리를 공통화 할 수 있다.
💡GlobalExceptionAdvice
@RestControllerAdvice
//Controllerexception 에서 발생하는 거는 다 잡음.
public class GlobalExceptionAdvice {
// 이 클래스 내에서 예외가 발생한 걸 찾음.
@ExceptionHandler
// exception 타입을 받아서 예외처리를 함.
// exception 전체를 받아서 할 수도 있지만 ~
// 사용자가 받는 것은 성공했는지 실패했는지를 판별할 때 알맞은 상태코드를 처리할 수 있어야 함.
//MethodArgumentNotValidException 는 bindingResult를 상속받고 있음!!!!
// 반드시 0보다 같거나 커야 합니다.
public ResponseEntity handleException(MethodArgumentNotValidException e ) {
// 예외가 발생하면 예외 클래스를 통해 발생하게 됨.
// 필요없는 데이터를 없앨 것. 없애는 걸 ErrorResponse.of() 에서 할 것임.
// MethodArgumentNotValidException 이 에러가 BindingResult 를 상속받고 있어서,
// 타입을 이렇게 받아도 되는 건가??????
BindingResult bindingResult = e.getBindingResult();
// 이게 필요없는 데이터를 없앤 결과 response .
ErrorResponse response = ErrorResponse.of(bindingResult);
return new ResponseEntity(response, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler
//RuntimeException을 상속 받고 있음.
// JVM 정상적인 작동 중에 발생하는 클래스.
// unchecked exception. 사용자가 예외 처리를 안해도 컴파일이 되기는 함. 코드가 실행이 되면 에러가 발생.
// 파라미터나 리턴 값에 문제가 있을 때. 제약 조건이 위배되었을 때 발생하는 예외임.
public ResponseEntity handleConstraintViolationException(ConstraintViolationException e) {
// constrainViolations 는 Set<ConstraintViolation<?>> 타입.
// s 인 이유가 있다고 했었는데...!!!!!!!!!
Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
ErrorResponse response = ErrorResponse.of(constraintViolations);
return new ResponseEntity(response, HttpStatus.BAD_REQUEST);
}
💡ErrorResponse
// 내부 클래스를 쓰는 이유: 하나의 클래스 안에서만 쓸 때. 하나에다가만 몰아서 쓰는 것. 내부에서만 쓰기 위해서 담아놨다.
// 우리가 감춘건 생성자. 생성자는 객체를 만드는 기능을 감춘걸 매세드 오버로딩을 통해서 of 메서드를 구현.
@Getter
// static 이 붙어서 new 를 안 붙이고 만들 수 있다.
// 그래서 .of 만 붙이고 생성할 수 있다.
public class ErrorResponse {
// dto 에서 발생하는 에러를 다 받음. 그래서 리스트로 받은 거임.
private List<FieldError> fieldErrors;
private List<ConstraintViolationError> violationErrors;
// private 접근제어자를 받음. 동일 클래스 내에서만 받음. 다른 곳에서는 생성자를 호출할 수 없도록 함.
// 내부에서 쓰겠다는 의미.
private ErrorResponse(List<FieldError> fieldErrors, List<ConstraintViolationError> violationErrors) {
this.fieldErrors = fieldErrors;
this.violationErrors = violationErrors;
}
// (4) BindingResult에 대한 ErrorResponse 객체 생성
// 동일 클래스에서 쓰고 있음, 생성자를 막아놓고, 불러와서 쓸 수 있음.
public static ErrorResponse of(BindingResult bindingResult) {
// new를 통해 안 들고 쓸 수 있어야 해서 static 이 붙은 거임.
return new ErrorResponse(FieldError.of(bindingResult), null);
// bindingResult 를 넣어서 호출하고 있음.
}
// (5) Set<ConstraintViolation<?>> 객체에 대한 ErrorResponse 객체 생성
public static ErrorResponse of(Set<ConstraintViolation<?>> violations) {
return new ErrorResponse(null, ConstraintViolationError.of(violations));
// 외부에서 에러를 of 라는 하나의 기능으로 만들고 싶은 거임.
// 발생하는 예외가 다를 때마다 다르게, 생성자를 만드는 것임.
}
//메서드 오버로딩. 파라미터의 타입이 다름.
// (6) Field Error 가공
@Getter
public static class FieldError {
private String field;
private Object rejectedValue;
private String reason;
private FieldError(String field, Object rejectedValue, String reason) {
this.field = field;
this.rejectedValue = rejectedValue;
this.reason = reason;
}
// FieldError.of 는 밑의 내용을 받아서 실행하는 거?????
public static List<FieldError> of(BindingResult bindingResult) {
// class 랑 이름이 같으니까 절대 경로를 지어주는 것임.
// 얘는 FieldError 임폴트 한 온전한 FieldError 인 것임.
// error 가 여러개 일 수 있으니 List 로 받는다??????
final List<org.springframework.validation.FieldError> fieldErrors =
bindingResult.getFieldErrors();
return fieldErrors.stream()
// error 를 새로운 FieldError 에 넣겠다.
// 밑에는 생성자 FieldError !!!!!!
// 돌명서 우리가 만드는 생성자 안에 필요한 데이터만 뽑아서 넣는 것.
.map(error -> new FieldError(
error.getField(),
// 오류가 발생한 필드 이름.
// 필드는 클래스에 포함된 변수. 객체의 속성을 정의하는 공간.
// 클래스 변수. 인스턴스 변수.
// 오류가 발생한 필드 이름 ? 없으면 빈 문자열 : 있으면 문자열로 전환해서 불러와라.
error.getRejectedValue() == null ?
"" : error.getRejectedValue().toString(),
error.getDefaultMessage()))
// 데이터를 가공한 뒤에 그 요소들을 수집해라.
// 스트림의 요소를 List, Set, Map. 등 다른 타입의 결과로 수집하고 싶을 때.
.collect(Collectors.toList());
}
}
'Spring > 예외처리' 카테고리의 다른 글
[Spring] 예외처리 - throw, throws (0) | 2025.04.10 |
---|---|
[Spring] 예외처리 - 비지니스 로직 (0) | 2024.06.15 |
[Spring] 예외처리 - 정적 팩토리 메서드 (0) | 2024.06.13 |