Validation

๐Ÿ” ๊ฐœ์š”

  • **Bean Validation(JSR 380)**์€ ์ž๋ฐ” ํ‘œ์ค€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ”„๋ ˆ์ž„์›Œํฌ.
  • Spring MVC๋Š” @Valid ๋˜๋Š” @Validated๋ฅผ ํ†ตํ•ด ์ด๋ฅผ ์ปจํŠธ๋กค๋Ÿฌ ๋ ˆ๋ฒจ์—์„œ ์‰ฝ๊ฒŒ ์ ์šฉ.
  • ์ž…๋ ฅ๊ฐ’ ์ œ์•ฝ ์กฐ๊ฑด์„ ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ ์–ธํ•˜์—ฌ, ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ๊ฐ€๋…์„ฑ์„ ๋†’์ธ๋‹ค.

โ˜๐Ÿป ํ•œ์ค„ ์š”์•ฝ

์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ์— @Valid/@Validated๋ฅผ ๋ถ™์ด๊ณ  BindingResult๋กœ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•˜์—ฌ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.


๐Ÿค” ์™œ ํ•„์š”ํ•œ๊ฐ€?

  • ํด๋ผ์ด์–ธํŠธ ์ž…๋ ฅ๊ฐ’์˜ ํ˜•์‹๊ณผ ๋ฒ”์œ„๋ฅผ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•จ
  • ์ž˜๋ชป๋œ ๊ฐ’์œผ๋กœ ์ธํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์˜ค๋ฅ˜ ์˜ˆ๋ฐฉ
  • ์„ ์–ธํ˜• ์ œ์•ฝ ์กฐ๊ฑด์œผ๋กœ ์ฝ”๋“œ ๊ฐ„๊ฒฐํ™”
  • ์ค‘๋ณต ๊ฒ€์‚ฌ ๋กœ์ง ์ œ๊ฑฐ

โš™๏ธ ์ฃผ์š” ๊ตฌ์„ฑ ์š”์†Œ

1. ๊ฒ€์‚ฌ ํŠธ๋ฆฌ๊ฑฐ

  • @Valid: Bean Validation ํ‘œ์ค€
  • @Validated: Spring ์ „์šฉ, ๊ทธ๋ฃน ๊ฒ€์ฆ(Group Validation) ์ง€์›

2. ์ œ์•ฝ ์กฐ๊ฑด ์–ด๋…ธํ…Œ์ด์…˜

Annotation์„ค๋ช…
@NotNullnull ๊ธˆ์ง€ (๋นˆ ๋ฌธ์ž์—ด์€ ํ—ˆ์šฉ)
@NotEmptynull ๋ฐ ๊ธธ์ด 0 ๊ธˆ์ง€ (์ปฌ๋ ‰์…˜ ํฌํ•จ)
@NotBlanknull, ๊ธธ์ด 0, ๊ณต๋ฐฑ ๋ฌธ์ž ๊ธˆ์ง€
@Size๋ฌธ์ž์—ด/์ปฌ๋ ‰์…˜ ํฌ๊ธฐ ์ œํ•œ
@Length๋ฌธ์ž์—ด ๊ธธ์ด ์ œํ•œ (Hibernate Validator)
@Email์ด๋ฉ”์ผ ํ˜•์‹ ๊ฒ€์ฆ
@Pattern์ •๊ทœ์‹ ํŒจํ„ด ์ผ์น˜ ๊ฒ€์ฆ
@Past / @Future๊ณผ๊ฑฐ/๋ฏธ๋ž˜ ๋‚ ์งœ์ธ์ง€ ํ™•์ธ
@Min / @Max์ˆซ์ž ๋ฒ”์œ„ ์ œํ•œ

3. BindingResult / Errors

  • ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ฒฐ๊ณผ๋ฅผ ๋‹ด๋Š” ๊ฐ์ฒด
  • @Valid/@Validated ๋ฐ”๋กœ ๋‹ค์Œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์„ ์–ธ
  • ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ง์ ‘ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

๐Ÿ”ง ์˜ˆ์‹œ

(A) ๊ธฐ๋ณธ ์‚ฌ์šฉ

@PostMapping("/users")
public String createUser(
    @Valid @ModelAttribute UserRequest request,
    BindingResult bindingResult
) {
    if (bindingResult.hasErrors()) {
        throw new ValidationFailedException(bindingResult);
    }
    // ๋กœ์ง ์ˆ˜ํ–‰
    return "redirect:/users";
}

(B) ๊ทธ๋ฃน ๊ฒ€์ฆ

public interface OnCreate {}
public interface OnUpdate {}
 
public class UserDto {
    @NotNull(groups = OnUpdate.class)
    private Long id;
 
    @NotBlank(groups = {OnCreate.class, OnUpdate.class})
    private String name;
}
 
@PostMapping("/users")
public String create(@Validated(OnCreate.class) UserDto dto, BindingResult br) { ... }

(C) JSON ์š”์ฒญ ๋ฐ”๋”” ๊ฒ€์ฆ

@PostMapping("/api/users")
@ResponseBody
public ApiResponse createUser(@Valid @RequestBody UserRequest request) {
    // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹คํŒจ ์‹œ MethodArgumentNotValidException ๋ฐœ์ƒ
    return ApiResponse.ok();
}

โš ๏ธ ์ฃผ์˜ํ•  ์ 

  • BindingResult๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ์œ ํšจ์„ฑ ์‹คํŒจ ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ (MethodArgumentNotValidException)
  • JSON ์š”์ฒญ ๊ฒ€์ฆ ์‹œ @RequestBody์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด์•ผ ํ•จ
  • @Valid์™€ @Validated๋Š” ๊ธฐ๋Šฅ์ด ๊ฐ™์ง€๋งŒ, ๊ทธ๋ฃน ๊ฒ€์ฆ์€ @Validated๋งŒ ์ง€์›
  • ์ปค์Šคํ…€ ์ œ์•ฝ ์กฐ๊ฑด์€ @Constraint๋กœ ์ •์˜ ๊ฐ€๋Šฅ

๐Ÿ”— ๊ด€๋ จ