Gradle 설정을 사용하였다.
implementation 'org.springframework.boot:spring-boot-starter-validation'
DTO클래스에서 view 모듈에서 클라이언트에게 받아오는 데이터 값을 바로 확인할 수 있도록 설계하였다.
public class SignupDto {
@NotBlank(message = "Please enter a username")
private String userName;
@Password
@NotBlank(message = "Please enter a password")
private String password;
@NotBlank(message = "Please enter a name")
@Email(message = "Please enter a valid email address")
private String email;
private String companyName;
private String address;
private boolean store;
private boolean user;
}
위 DTO 클래스에서 알 수 있듯 @NotBlank어노테이션으로 빈칸에 대한 데이터를 불가능하도록 설정하였고, Email 검증등 다양한 어노테이션을 추가하였다.
@Password라는 어노테이션이 있는데 이건 나중에 따로 검증을 위해 커스텀 어노테이션이다. 다음 블로그에서 따로 상세히 작성하겠다.
컨트롤러에 유효성 검사 적용을 위한 @Valid 어노테이션도 적용하였다.
public class UserSignupViewController {
private final RestTemplate restTemplate = new RestTemplate();
@GetMapping("/signup")
public String showSignUpForm() {
return "signup_form";
}
@RequestMapping(value = "/signup", method = RequestMethod.POST)
public ResponseEntity<String> registerUser(@RequestBody @Valid SignupDto signupDTO, @Value("${api.url}") String url) {
ResponseEntity<String> signupStatus = restTemplate.postForEntity( url + "/user/signup", signupDTO, String.class);
return signupStatus;
}
}
api 모듈쪽에 DTO를 파라미터로 받을때 추가해줘도 되지만 처음 데이터가 들어올때부터 검증을 위해 UI모듈에 @Valid 어노테이션을 추가하여 유효성 검사를 진행하였다.
다음과 같은 방법으로 BindingResult 객체를 파라미터로 받아 유효성 검사결과를 확인할 수 있다.
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController
@Validated
public class UserController {
@PostMapping("/users")
public ResponseEntity<String> createUser(@Valid @RequestBody User user, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
// 유효성 검사 실패 시 처리
return ResponseEntity.badRequest().body("Validation errors: " + bindingResult.getAllErrors());
}
// 유효성 검사 통과 시 처리
return ResponseEntity.ok("User created successfully");
}
}
@Valid는 프론트 컨트롤러인 디스패처 서블릿을 통해 컨트롤러로 전달된다. 이 때 전달과정에서 메소드 객체를 만들어주는 ArgumentResolver가 동작하는데, @Valid 역시 ArgumentResolver에 의해 처리가 된다.
이러한 같은 이유로 @Valid는 컨트롤러에서만 동작하며 다른계층에선 검증이 되지않는다.
다른 계층에서 파라미터를 검증하기 위해선 @Validated와 결합 되어야 한다.
@Service
@Validated
public class UserService {
public void addUser(@Valid AddUserRequest addUserRequest) {
...
}
}
다음과 같이 클래스에 @Validated를 붙여주고 유효성 검증할 파라미터에 @Valid를 붙여주면 된다.
특정 ArgumnetResolver에 의해 유효성 검사가 진행되었던 @Valid와 달리, @Validated는 AOP 기반으로 메소드 요청을 인터셉터하여 처리된다. @Validated를 클래스 레벨에 선언하면 해당 클래스에 유효성 검증을 위한 AOP의 어드바이스 또는 인터셉터(MethodValidationInterceptor)가 등록된다. 이러한 이유로 @Validated를 사용하면 컨트롤러, 서비스, 레포지토리 등 계층에 무관하게 스프링 빈이라면 유효성 검증을 진행할 수 있다.
이러한 이유로 @Valid에 의한 예외는 MethodArgumentNotValidException이며, @Validated에 의한 예외는 ConstraintViolationException이다. 이를 알고 있으면 나중에 예외 처리를 할 때 도움이 된다.
출처 및 참고
https://mangkyu.tistory.com/174
https://ajdahrdl.tistory.com/138