User.java
public class User {
@NotEmpty
@Size(min = 1,max = 100)
private String name;
@Min(1)
@NotNull
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Error.java
public class Error {
private String field;
private String message;
private String invalidValue;
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getInvalidValue() {
return invalidValue;
}
public void setInvalidValue(String invalidValue) {
this.invalidValue = invalidValue;
}
@Override
public String toString() {
return "Error{" +
"field='" + field + '\'' +
", message='" + message + '\'' +
", invalidValue='" + invalidValue + '\'' +
'}';
}
}
ErrorResponse.java
public class ErrorResponse {
String statusCode;
String requestUrl;
String code;
String message;
String resultCode;
List<Error> errorList;
public String getStatusCode() {
return statusCode;
}
public void setStatusCode(String statusCode) {
this.statusCode = statusCode;
}
public String getRequestUrl() {
return requestUrl;
}
public void setRequestUrl(String requestUrl) {
this.requestUrl = requestUrl;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getResultCode() {
return resultCode;
}
public void setResultCode(String resultCode) {
this.resultCode = resultCode;
}
public List<Error> getErrorList() {
return errorList;
}
public void setErrorList(List<Error> errorList) {
this.errorList = errorList;
}
@Override
public String toString() {
return "ErrorResponse{" +
"statusCode='" + statusCode + '\'' +
", requestUrl='" + requestUrl + '\'' +
", code='" + code + '\'' +
", message='" + message + '\'' +
", resultCode='" + resultCode + '\'' +
", errorList=" + errorList +
'}';
}
}
ApiController.java
* @validated 사용
@RestController
@RequestMapping("/api/user")
@Validated // @Validated
public class ApiController {
/*
* (required = false) 필수값 아님, 해당 값이 없더라도 동작하고 null값 지정, default는 true
* validated 어노테이션을 사용하여 해당 GET 방식 호출시 파라미터들을 검증할 수 있음
*/
@GetMapping("")
public User get(
@Size(min=2)
@RequestParam String name,
@NotNull
@Min(1)
@RequestParam Integer age){
User user = new User();
user.setAge(age); // NPE 발생, 500에러
user.setName(name);
int a = 10 + age;
return user;
}
@PostMapping("")
public User post(@Valid @RequestBody User user){
System.out.println(user);
return user;
}
// 우선순위는 컨틀롤러 ExceptionHandler가 Global 보다 우선.
// 해당 컨틀롤러에 클라이언트가 요청시 Exception 발생한 것들중에 ExceptionHandler 존재하는 것 캐치.
// @ExceptionHandler(value = MethodArgumentNotValidException.class)
// public ResponseEntity MethodArgumentNotValidException(MethodArgumentNotValidException e){
// System.out.println("ApiController @MethodArgumentNotValidException(value = MethodArgumentNotValidException.class) : ");
// return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage()); // 해당 에러 메시지내용 응답
// }
}
ApiControllerAdvice.java
* 특정 클래스에 Advice 적용
//@RestControllerAdvice
@RestControllerAdvice(basePackageClasses = ApiController.class)
//@RestControllerAdvice(basePackages = "com.example.exception.controller") 해당 패키지 내 Exception 을 잡음
public class ApiControllerAdvice {
// Exception 에러를 핸들러로 잡아서 해당 메소드 실행
@ExceptionHandler(value = Exception.class)
public ResponseEntity exception(Exception e){
System.out.println("@ExceptionHandler(value = Exception.class) : ");
System.out.println(e.getClass().getName());
System.out.println(e.getLocalizedMessage()); // 해당 Exception 내용
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(""); // 빈 응답
}
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public ResponseEntity MethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest httpServletRequest){
System.out.println("@MethodArgumentNotValidException(value = MethodArgumentNotValidException.class) : ");
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 errorMsg = new Error();
errorMsg.setField(fieldName);
errorMsg.setMessage(message);
errorMsg.setInvalidValue(value);
errorList.add(errorMsg);
});
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){
System.out.println("@ConstraintViolationException(value = ConstraintViolationException.class) : ");
List<Error> errorList = new ArrayList<>();
// e.getConstraintViolations() 에러 정보
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 errorMsg = new Error();
errorMsg.setField(field);
errorMsg.setMessage(message);
errorMsg.setInvalidValue(invalidValue);
errorList.add(errorMsg);
});
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){
System.out.println("@MissingServletRequestParameterException(value = MissingServletRequestParameterException.class) : ");
List<Error> errorList = new ArrayList<>();
String fieldName = e.getParameterName();
String value = e.getMessage();
Error errorMsg = new Error();
errorMsg.setField(fieldName);
errorMsg.setInvalidValue(value);
errorList.add(errorMsg);
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); // 해당 에러 메시지내용 응답
}
}
HTTP 요청 BODY
{
"name":"",
"age":0
}
HTTP 응답 BODY
{
"statusCode": "400 BAD_REQUEST",
"requestUrl": "/api/user",
"code": null,
"message": "",
"resultCode": "FAIL",
"errorList":[
{
"field": "name",
"message": "크기가 1에서 100 사이여야 합니다",
"invalidValue": ""
},
{
"field": "name",
"message": "비어 있을 수 없습니다",
"invalidValue": ""
},
{
"field": "age",
"message": "1 이상이어야 합니다",
"invalidValue": "0"
}
]
}
'Spring > 98. Infra' 카테고리의 다른 글
4. Spring Filter와 Interceptor (0) | 2022.11.14 |
---|---|
2. Spring Boot Exception (0) | 2022.11.07 |
1. Spring Boot Validation (0) | 2022.11.07 |