Validation
2024. 10. 9. 17:39ㆍSpring Framework/Web on Servlet Stack
스프링 MVC는 컨트롤러 메서드에서 유효성 검사(Validation)를 지원하며, 이를 통해 요청 데이터가 정확한지 검증할 수 있습니다. 유효성 검사는 두 가지 수준에서 적용될 수 있습니다.
- 메서드 파라미터 단위의 유효성 검사:
@ModelAttribute
,@RequestBody
,@RequestPart
에 적용할 수 있으며, 이러한 파라미터가@Valid
나@Validated
로 주석 처리되면 개별적으로 검증됩니다. - 메서드 레벨의 유효성 검사: 메서드 파라미터나 메서드 자체에
@Constraint
(예:@Min
,@NotBlank
등)를 선언하여 검증할 수 있습니다. 메서드 검증은 메서드 파라미터뿐만 아니라 중첩된 객체의 유효성 검사까지 적용됩니다.
주요 개념
@Valid
와@Validated
: 요청 데이터를 바인딩한 객체에 대해 유효성 검사를 수행합니다. 이때Errors
또는BindingResult
파라미터가 있으면, 컨트롤러 메서드가 호출되고 유효성 검사 오류가 전달됩니다. 그렇지 않으면MethodArgumentNotValidException
예외가 발생합니다.- 메서드 검증: 파라미터나 메서드 자체에 유효성 검증 애너테이션(예:
@NotNull
,@Min
,@NotBlank
)을 직접 선언하면 메서드 단위의 유효성 검사가 수행됩니다. 이 경우HandlerMethodValidationException
이 발생할 수 있습니다. - 전역 Validator 설정: 전역적으로 Validator를 설정하거나 컨트롤러 단위로
@InitBinder
를 통해 로컬 Validator를 설정할 수 있습니다.
1. @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
를 반환하며, 오류를 처리할 수 있습니다.
2. @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
예외가 발생합니다.
3. 메서드 수준의 유효성 검사
메서드 파라미터나 반환 값에 유효성 검사를 직접 선언할 수 있습니다.
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
: 유효성 검사가 실패하면 이 예외가 발생하며, 이를 통해 오류를 처리할 수 있습니다.
4. 전역 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를 설정하는 방법입니다. 이 설정은 모든 컨트롤러에 적용됩니다.
5. 예외 처리
유효성 검사 오류가 발생했을 때, 이를 처리하는 방법 중 하나는 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
'Spring Framework > Web on Servlet Stack' 카테고리의 다른 글
Controller Advice (0) | 2024.10.09 |
---|---|
Exceptions (0) | 2024.10.09 |
@InitBinder (0) | 2024.10.09 |
Model (0) | 2024.10.09 |
Handler Method : Jackson JSON (0) | 2024.10.09 |