error
package com.example.exception.dto;
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;
}
}
ErrorResponse
package com.example.exception.dto;
import java.util.List;
// 사용자가 알아보기 좋게 에러 메세지 출력하기 위해 만듬
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;
}
}
User
package com.example.exception.dto;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class User {
@NotEmpty
@Size(min = 1, max = 10)
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 +
'}';
}
}
api Controller
package com.example.exception.controller;
import com.example.exception.dto.User;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@RestController
@RequestMapping("/api/user")
@Validated // 컨트롤러 단위에 작성, RequestParam 또한 검증 하도록
public class ApiController {
@GetMapping("")
public User get(
@Size(min = 2)
@RequestParam String name,
@NotNull
@Min(1)
@RequestParam Integer age){
User user = new User();
user.setName(name);
user.setAge(age);
// NullPointerException 고의로 에러 발생시키기 위해
// int a = 10 + age;
return user;
}
@PostMapping
public User post(@Valid @RequestBody User user){
System.out.println(user);
return user;
}
// 여기다 붙여넣기 하면 이 컨트롤러에서 발생하는 Exception만 잡음
// 글로벌 핸들러 보다 여기가 우선순위 더 높음
// @ExceptionHandler(value = MethodArgumentNotValidException.class)
// public ResponseEntity MethodArgumentNotValidException(MethodArgumentNotValidException e){
// System.out.println("api controller");
// return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("다시하자");
// }
}
ApiControllerAdvice
package com.example.exception.advice;
import com.example.exception.controller.ApiController;
import com.example.exception.dto.Error;
import com.example.exception.dto.ErrorResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
// Apicontroller 안에만
@RestControllerAdvice(basePackageClasses = ApiController.class)
public class ApiControllerAdvice {
@ExceptionHandler(value = Exception.class)
public ResponseEntity exception(Exception e){
System.out.println(e.getClass().getName());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("");
}
@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();
System.out.println("---------------------");
System.out.println(fieldName);
System.out.println(message);
System.out.println(value);
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);
}
// name = a, age = 0 넣은 경우 발생하는 Exception 처리한것
// 이 Exception의 경우 어떠한 필드가 잘 못 되었는지 정보를 담고 있다!!!
@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();
System.out.println("----------------");
System.out.println(field);
System.out.println(message);
System.out.println(invalidValue);
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);
}
// 둘다 빈 값 넣었을 때 발생한 Exception
@ExceptionHandler(value = MissingServletRequestParameterException.class)
public ResponseEntity Missing(MissingServletRequestParameterException e, HttpServletRequest httpServletRequest){
List<Error> errorList = new ArrayList<>();
String fieldName = e.getParameterName();
String invalidValue= e.getMessage();
System.out.println(fieldName);
System.out.println(invalidValue);
Error errorMessage = new Error();
errorMessage.setField(fieldName);
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);
}
}