요르딩딩
@ExceptionHandler, @Valid 본문
728x90
반응형
이번시간에는 요청파라미터의 @Valid를 활용한 유효성 체크와 @ExceptionHandler를 활용한 예외처리에 대해 공부해보겠습니다.
우선, @Valid를 사용하기 위해 pom.xml에 아래 라이브러리를 추가해줍니다.
<!-- hibernate-validator 5~6 버전대랑 javax.validation 1.x.x는 호환이 안된다. -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.10.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
그리고, 유효성 체크를 진행할 DTO에 어노테이이션을 적용하여, 체크해줍니다.
다만, collection은 체크를 해주지 않으므로, 추가로 @Valid 어노테이션을 붙여주어야합니다.
package com.**.controller.request;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import java.util.List;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class TransferRequest {
@NotBlank
private String accountKey;
@Positive
private int companyNo;
@NotNull
@Valid
private List<Accounts> depAccts;
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public static class Accts {
@Positive
private int employeeNo;
@NotBlank
private String bankCode;
public int getEmployeeNo() {
return employeeNo;
}
public String getBankCode() {
return bankCode;
}
}
public String getAccountKey() {
return accountConnectKey;
}
public void setAccountKey(String accountKey) {
this.accountKey = accountKey;
}
public int getCompanyNo() {
return companyNo;
}
public void setCompanyNo(int companyNo) {
this.companyNo = companyNo;
}
}
유효성 체크를 할 객체에 @Valid를 붙여줍니다.
이제 유효성 체크에 걸리게 되면 Exception이 발생하게 됩니다.
이때 아래 주석처럼 해당 컨트롤러내에 다이렉트로 적용시켜줄 수도 있지만, global하게 처리하도록 해보겠습니다.
package com.**.controller;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@RestController
@RequestMapping("/svc/salary")
public class SalaryController {
protected Logger logger = LogManager.getLogger(this.getClass());
@Autowired
private SalaryService SalaryService;
@PostMapping("/reservation")
public Result SalaryReservation(@Valid @RequestBody TransferRequest transferRequest) throws Exception {
Result result = new Result();
result = SalaryService.SalaryReservation(transferRequest);
return result;
}
@PostMapping("/result")
public LuluResult SalaryResult(@Valid @RequestBody TransferRequest transferRequest) throws Exception {
Result result = new Result();
result = SalaryService.SalaryResult(transferRequest);
return result;
}
// /*
// * 예외처리
// */
// @ExceptionHandler(MethodArgumentNotValidException.class)
// public ErrorResponse processValidationError(MethodArgumentNotValidException exception) {
// BindingResult bindingResult = exception.getBindingResult();
//
// ErrorResponse errorResponse = new ErrorResponse();
//
// StringBuffer errorMsg = new StringBuffer();
// for (FieldError fieldError : bindingResult.getFieldErrors()) {
// errorMsg.append(fieldError.getField()).append(", ");
// }
//
// errorResponse.setResultCode(400);
// errorResponse.setResultMsg("[" + errorMsg.substring(0, errorMsg.length()-2).toString() + "] 필수파라미터 체크 바랍니다.");
//
// return errorResponse;
// }
}
exceptionAdvisor에 @RestControllerAdvice 어노테이션을 활용해 Exception을 커스텀하여 처리하도록 하겠습니다.
아래 코드는 특정 컨트롤러만 적용할 수 있도록 basePackageClasses를 적용하였고, 아래와 같이 필수 파라미터를 체크하는 예외를 커스텀 하여 적용하였습니다.
여기서 특정회사의 프레임워크를 사용할 경우, 예외 발생시 해당 프레임워크의 예외처리가 먼저 적용되어 아래로직까지 오지 않는 경우가 발생 할 수 있으므로, @Order 어노테이션을 활용하여, 가장먼저 적용되도록 적용시켜주어야 합니다.
HTTP status Code에 적용하기 위해서는 @ResponseStatus(HttpStatus.BAD_REQUEST)을 추가해 주어야합니다.
package com.**.common.exceptionAdvisor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice(basePackageClasses = SalaryBatchController.class) // body 사용가능
@Order(Ordered.HIGHEST_PRECEDENCE) // ruruExcptrion 보다 먼저
public class ExceptionAdvisor {
protected Logger logger = LogManager.getLogger(this.getClass());
@ResponseStatus(HttpStatus.BAD_REQUEST) // HTTP Status Code 적용
@ExceptionHandler(MethodArgumentNotValidException.class)
public ErrorResponse processValidationError(MethodArgumentNotValidException exception) {
BindingResult bindingResult = exception.getBindingResult();
ErrorResponse errorResponse = new ErrorResponse();
StringBuffer errorMsg = new StringBuffer();
for (FieldError fieldError : bindingResult.getFieldErrors()) {
errorMsg.append(fieldError.getField()).append(", ");
}
errorResponse.setResultCode(HttpStatus.BAD_REQUEST.value());
errorResponse.setResultMsg("[" + errorMsg.substring(0, errorMsg.length() - 2).toString() + "] 필수파라미터 체크 바랍니다.");
return errorResponse;
}
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) // HTTP Status Code 적용
@ExceptionHandler({ Exception.class })
protected ErrorResponse handleServerException(Exception exception) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setResultCode(HttpStatus.BAD_REQUEST.value());
errorResponse.setResultMsg(exception.getMessage());
return errorResponse;
}
}
728x90
반응형
'[Web] > [Spring]' 카테고리의 다른 글
Spring - Interceptor (0) | 2022.11.11 |
---|---|
Spring - Filter (0) | 2022.11.11 |
[Spring] branch 생성 및 적용하는법 (0) | 2022.09.20 |
JUnit 테스트하는 방법 (0) | 2022.09.14 |
DTO를 사용해보자 (0) | 2022.08.12 |
Comments