13. Bean Validation

์ž…๋ ฅ๊ฐ’์ด ๊ณต๋ž€์ด๋ฉด ์•ˆ๋˜๊ฑฐ๋‚˜ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋Š” ์ˆซ์ž์˜ ๋ฒ”์œ„๊ฐ€ ์ œํ•œ๋˜์–ด ์žˆ๋Š” ๋“ฑ, ๊ฒ€์ฆ์ด ํ•„์š”ํ•œ ํ•ญ๋ชฉ์€ ์‚ฌ์‹ค ์–ด๋Š ์„œ๋น„์Šค๋‚˜ ๋น„์Šทํ•  ๊ฒƒ์ด๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์Šคํ”„๋ง์€ ๊ธฐ๋ณธ์ ์ธ ๊ฒ€์ฆ ํ•ญ๋ชฉ๋“ค์„ ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค. ์ด๊ฒƒ์„ ํ™œ์šฉํ•œ ๊ฒ€์ฆ ๋ฐฉ์‹์„ Bean Validation ์ด๋ผ๊ณ  ํ•œ๋‹ค.

1๏ธโƒฃ ย  Bean Validation - FieldError

  • Item ๊ฐ์ฒด์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด @ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•œ๋‹ค.
  • ๊ฒ€์ฆ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•  @ModelAttribute ์•ž์— @Validated ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

public class Item {

   private Long id;

  @NotBlank //๊ณต๋ฐฑ, ๋„์–ด์“ฐ๊ธฐ๋ฅผ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Œ.
   private String itemName;

  @NotNull //null์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Œ.
  @Range(min = 1000, max = 1000000) //์ž…๋ ฅ ๊ฐ€๋Šฅํ•œ ์ˆซ์ž ๋ฒ”์œ„๋ฅผ ์ง€์ •.
   private Integer price;

  @NotNull
  @Max(value = 9999) //์ž…๋ ฅ ๊ฐ€๋Šฅํ•œ ์ตœ๋Œ€๊ฐ’์„ ์ง€์ •.
  Integer quantity;

}

@PostMapping("/add")
public String addItemV6(@Validated @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) {
    (...)
}

2๏ธโƒฃ ย  errors.properties

  • Bean Validation ์œผ๋กœ ์ถœ๋ ฅ๋˜๋Š” ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ข€ ๋” ์ž์„ธํžˆ ์ž‘์„ฑํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด properties ํŒŒ์ผ์— ๋ฉ”์‹œ์ง€๋ฅผ ๋“ฑ๋กํ•˜๋ฉด ๋œ๋‹ค.
#Bean Validation ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€
NotBlank={0} ๊ณต๋ฐฑX
Range={0}, {2} ~ {1} ํ—ˆ์šฉ
Max={0}, ์ตœ๋Œ€ {1}

3๏ธโƒฃ ย  Bean Validation - ObjectError

  • ํŠน์ • ํ•„๋“œ(FieldError) ๊ฐ€ ์•„๋‹Œ ์˜ค๋ธŒ์ ํŠธ ๊ด€๋ จ ์˜ค๋ฅ˜(ObjectError) ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด @ScriptAssert() ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.
@ScriptAssert(lang = "javascript", script = "_this.price * _this.quantity >= 10000", message = "์ดํ•ฉ๊ณ„๋Š” 10,000์› ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.")
public class Item {
   (...)
}
  • ๊ทธ๋ ‡์ง€๋งŒ ์‹ค์ œ ์‚ฌ์šฉํ•ด๋ณด๋ฉด ์ œ์•ฝ์ด ๋งŽ๊ณ  ๋ณต์žกํ•˜๊ธฐ์—, ObjectError์˜ ๊ฒฝ์šฐ ์ž๋ฐ” ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

4๏ธโƒฃ ย  groups

  • Bean Validation์€ ์ด๋ ‡๊ฒŒ ํŽธ๋ฆฌํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด์ฃผ์ง€๋งŒ ๋“ฑ๋ก ํผ๊ณผ ์ˆ˜์ • ํผ์—์„œ์˜ ๊ฒ€์ฆ ์š”๊ตฌ์‚ฌํ•ญ์ด ๋‹ค๋ฅธ ๊ฒฝ์šฐ ์ ์šฉํ•˜๊ธฐ ํž˜๋“ค์–ด์ง„๋‹ค.
  • ์ด ๊ฒฝ์šฐ ๋ฐฉ๋ฒ•์€ ๋‘ ๊ฐ€์ง€์ธ๋ฐ, ์ฒซ๋ฒˆ์งธ๋กœ groups ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ฐ์ฒด์— ์ ์šฉํ•œ Bean Validation ์–ด๋…ธํ…Œ์ด์…˜์— ํ•ด๋‹น ๊ฒ€์ฆ์‚ฌํ•ญ์„ ์ ์šฉํ•  ํด๋ž˜์Šค๋“ค์„ ์ ์–ด๋„ฃ์–ด ๊ทธ๋ฃนํ™”ํ•œ๋‹ค.
  • ์ปจํŠธ๋กค๋Ÿฌ์˜ @Validated ์–ด๋…ธํ…Œ์ด์…˜์— ์–ด๋–ค ๊ทธ๋ฃน์˜ ๊ฒ€์ฆ ํ•ญ๋ชฉ์„ ์ ์šฉํ•  ๊ฒƒ์ธ์ง€๋ฅผ ์ ์–ด๋„ฃ๋Š”๋‹ค.

public class Item {

   @NotNull(groups = UpdateCheck.class)
    private Long id;

   @NotBlank(groups = {SaveCheck.class, UpdateCheck.class})
    private String itemName;

   @NotNull(groups = {SaveCheck.class, UpdateCheck.class})
   @Range(min = 1000, max = 1000000, groups = {SaveCheck.class, UpdateCheck.class})
    private Integer price;

   @NotNull(groups = {SaveCheck.class, UpdateCheck.class})
   @Max(value = 9999, groups = {SaveCheck.class})
    private Integer quantity;

}

@PostMapping("/add")
public String addItemV6(@Validated(SaveCheck.class) @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) {
    (...)
}

5๏ธโƒฃ ย  ํผ ๊ฐ์ฒด ์ƒ์„ฑ

  • ์œ„ groups ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ์˜ ๋ณต์žก๋„๊ฐ€ ์ฆ๊ฐ€ํ•œ๋‹ค.
  • ๊ฒ€์ฆ ํ•ญ๋ชฉ์„ ๋ถ„๋ฆฌํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๋Š” ๋“ฑ๋ก ํผ๊ณผ ์ˆ˜์ • ํผ์—์„œ ์ „์†กํ•˜๋Š” ํ•„๋“œ๊ฐ€ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
  • ์ด ๊ฒฝ์šฐ ๋“ฑ๋ก, ์ˆ˜์ • ํผ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ๋ฐ›์„ ๊ฐ์ฒด๋ฅผ ๋”ฐ๋กœ ์ƒ์„ฑํ•ด์„œ @ModelAttribute ์— ๋‹ด์€ ํ›„ ๊ฒ€์ฆ์„ ์ˆ˜ํ–‰ํ•œ ์ดํ›„ Item ๊ฐ์ฒด์— ๋ฐ์ดํ„ฐ๋ฅผ ์„ธํŒ…ํ•˜๋ฉด ๊ฐ„๋‹จํ•ด์ง„๋‹ค.

public class ItemSaveForm {

    @NotBlank
    private String itemName;

    @NotNull
    @Range(min = 1000, max = 1000000)
    private Integer price;

    @NotNull
    @Max(value = 9999)
    private Integer quantity;

}

public class ItemUpdateForm {

    @NotNull
    private Long id;

    @NotBlank
    private String itemName;

    @NotNull
    @Range(min = 1000, max = 1000000)
    private Integer price;

    //[์ˆ˜์ •] ์—์„œ ์ˆ˜๋Ÿ‰์€ ์ž์œ ๋กญ๊ฒŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.
    private Integer quantity;

}

/* ์ปจํŠธ๋กค๋Ÿฌ */
public String edit(@PathVariable Long itemId, @Validated @ModelAttribute("item") ItemUpdateForm form, BindingResult bindingResult) {
}