https://sundaland.tistory.com/334
[ ▶ Validation ]
스프링 MVC는 컨트롤러 메서드에서 유효성 검사(Validation)를 지원하며, 이를 통해 요청 데이터가 정확한지 검증할 수 있다. 유효성 검사는 두 가지 수준에서 적용될 수 있다.
- 메서드 파라미터 단위의 유효성 검사: @ModelAttribute, @RequestBody, @RequestPart에 적용할 수 있으며, 이러한 파라미터가 @Valid나 @Validated로 주석 처리되면 개별적으로 검증된다.
- 메서드 레벨의 유효성 검사: 메서드 파라미터나 메서드 자체에 @Constraint(@Min, @NotBlank 등)를 선언하여 검증할 수 있다. 메서드 검증은 메서드 파라미터뿐만 아니라 중첩된 객체의 유효성 검사까지 적용된다.
[ ▷ 주요 개념 ]
- @Valid와 @Validated: 요청 데이터를 바인딩한 객체에 대해 유효성 검사를 수행한다. 이때 Errors 또는 BindingResult 파라미터가 있으면, 컨트롤러 메서드가 호출되고 유효성 검사 오류가 전달된다. 그렇지 않으면 MethodArgumentNotValidException 예외가 발생한다.
- 메서드 검증: 파라미터나 메서드 자체에 유효성 검증 애너테이션(예: @NotNull, @Min, @NotBlank)을 직접 선언하면 메서드 단위의 유효성 검사가 수행된다. 이 경우 HandlerMethodValidationException이 발생할 수 있다.
- 전역 Validator 설정: 전역적으로 Validator를 설정하거나 컨트롤러 단위로 @InitBinder를 통해 로컬 Validator를 설정할 수 있다.
[ ▷ @Valid와 Errors를 사용한 유효성 검사 ]
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class AccountController {
@PostMapping("/accounts")
public String handleAccount(@Valid @ModelAttribute AccountForm form, Errors errors) {
if (errors.hasErrors()) {
// 유효성 검사 실패 시 처리
return "errorPage";
}
// 성공 시 처리 로직
return "successPage";
}
}
- @Valid: AccountForm 객체에 대해 유효성 검사를 수행한다. 이 객체의 필드에 선언된 검증 애너테이션(@NotBlank, @Size)에 따라 유효성 검사가 실행된다.
- Errors: 유효성 검사 실패 시 오류 정보를 전달하는 파라미터이다. 유효성 검사 오류가 있으면 errors.hasErrors()가 true를 반환하며, 오류를 처리할 수 있다.
[ ▷ @RequestBody를 사용한 JSON 데이터 유효성 검사 ]
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@PostMapping("/users")
public ResponseEntity<String> createUser(@Valid @RequestBody User user) {
// 유효성 검사 통과 후 처리 로직
return ResponseEntity.ok("User created successfully!");
}
}
- @RequestBody: JSON 요청 본문을 User 객체로 변환한 후, 유효성 검사를 수행한다.
- @Valid: User 객체의 필드에 대해 유효성 검사를 적용한다. 오류가 있을 경우 MethodArgumentNotValidException 예외가 발생한다.
[ ▷ 메서드 수준의 유효성 검사 ]
메서드 파라미터나 반환 값에 유효성 검사를 직접 선언할 수 있다.
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ProductController {
@GetMapping("/product")
public String getProduct(
@RequestParam @NotBlank String name,
@RequestParam @Min(1) int quantity) {
return "Product name: " + name + ", Quantity: " + quantity;
}
}
- @NotBlank, @Min: 메서드 파라미터에 직접 유효성 검사를 선언했다. name은 비어 있으면 안 되며, quantity는 1 이상의 값을 가져야 한다.
- HandlerMethodValidationException: 유효성 검사가 실패하면 이 예외가 발생하며, 이를 통해 오류를 처리할 수 있다.
[ ▷ 전역 Validator 설정 ]
전역적으로 Validator를 설정하면, 컨트롤러 전체 또는 특정 파라미터에 대해 유효성 검사를 적용할 수 있다.
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.Validator;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public Validator getValidator() {
return new CustomValidator(); // 커스텀 Validator 설정
}
}
- getValidator(): 전역적으로 커스텀 Validator를 설정하는 방법이다. 이 설정은 모든 컨트롤러에 적용된다.
[ ▷ 예외 처리 ]
유효성 검사 오류가 발생했을 때, 이를 처리하는 방법 중 하나는 ResponseEntityExceptionHandler 또는 @ExceptionHandler를 사용하는 것이다.
▼ @ExceptionHandler를 사용한 예외 처리
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.MethodArgumentNotValidException;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<String> handleValidationException(MethodArgumentNotValidException ex) {
return new ResponseEntity<>("Validation failed: " + ex.getMessage(), HttpStatus.BAD_REQUEST);
}
}
- @ControllerAdvice: 전역 예외 처리를 담당하는 클래스이다. 모든 컨트롤러에서 발생하는 예외를 처리할 수 있다.
- @ExceptionHandler: 특정 예외(MethodArgumentNotValidException)가 발생했을 때 이 메서드를 통해 오류 응답을 생성한다.
[ ▷ 요약 ]
- @Valid와 @Validated는 요청 데이터를 바인딩한 객체에 대해 유효성 검사를 수행한다. Errors 또는 BindingResult를 함께 사용하면 유효성 검사가 실패해도 컨트롤러 메서드가 호출된다.
- 메서드 수준 유효성 검사는 메서드 파라미터나 반환 값에 직접 유효성 검사를 선언할 수 있으며, HandlerMethodValidationException을 통해 오류를 처리할 수 있다.
- 전역적으로 Validator를 설정하거나, @InitBinder 메서드를 통해 컨트롤러별로 커스텀 Validator를 설정할 수 있다.
- 예외 처리 방식으로는 ResponseEntityExceptionHandler 또는 @ExceptionHandler를 사용하여 유효성 검사 실패 시 발생하는 예외를 처리할 수 있다.
이 방식은 웹 애플리케이션에서 사용자의 입력 데이터를 안전하고 정확하게 검증하는 데 매우 유용하며, 유효성 검사를 통해 비즈니스 로직에서 잘못된 입력을 방지할 수 있다.
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
public class AccountForm {
@NotBlank(message = "Username is required")
@Size(min = 3, max = 20, message = "Username must be between 3 and 20 characters")
private String username;
@NotBlank(message = "Email is required")
private String email;
// 기본 생성자
public AccountForm() {}
// 생성자
public AccountForm(String username, String email) {
this.username = username;
this.email = email;
}
// Getter와 Setter
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
public class User {
@NotBlank(message = "Username is required")
private String username;
@NotBlank(message = "Password is required")
@Size(min = 6, message = "Password must be at least 6 characters long")
private String password;
// 기본 생성자
public User() {}
// 생성자
public User(String username, String password) {
this.username = username;
this.password = password;
}
// Getter와 Setter
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
[ 참고 ] : https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-validation.html
'Web on Servlet Stack' 카테고리의 다른 글
Functional Endpoints Overview (0) | 2024.10.14 |
---|---|
Exceptions (0) | 2024.10.14 |
@InitBinder (0) | 2024.10.14 |
Model (0) | 2024.10.14 |
Handler Method : Jackson JSON (0) | 2024.10.11 |