오류메시지를 조금 더 친절하게 안내하기 위한 작업
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;
@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();
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);
}
}
각 에러마다 정의하여 깔끔하게 전달할수있다.
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;
}
}
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;
}
}
package com.example.exception.controller;
import com.example.exception.dto.User;
import org.springframework.validation.annotation.Validated;
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
public class ApiController {
@GetMapping("")
public User get(
@Size(min=2)
@RequestParam String name,
@NotNull
@Min(1)
@RequestParam Integer age){
//required false: RequestParam이 없어도 동작하되 null값이 됨
User user=new User();
user.setName(name);
user.setAge(age);
return user;
}
@PostMapping("")
public User post(@Valid @RequestBody User user){
System.out.println(user);
return 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 +
'}';
}
}