# Bean Validation - ๊ฒ€์ฆ ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ
Study Repository

Bean Validation - ๊ฒ€์ฆ ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ

by rlaehddnd0422

Bean Validation

๊ฒ€์ฆ๊ธฐ๋Šฅ์„ ๋งค๋ฒˆ ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ๋„ ์ข€ ๊ท€์ฐฎ์€ ์ผ์ž…๋‹ˆ๋‹ค.

ํŠน์ • ํ•„๋“œ์— ๋Œ€ํ•œ ๊ฒ€์ฆ ๋กœ์ง์€ ๋Œ€๋ถ€๋ถ„ ๋นˆ ๊ฐ’์ธ์ง€, ํŠน์ • ํฌ๊ธฐ๋ฅผ ๋„˜๋Š”์ง€์™€ ๊ฐ™์ด ๋งค์šฐ ์ผ๋ฐ˜์ ์ธ ๋กœ์ง์ธ๋ฐ ์ด๋Ÿฐ ์ผ๋ฐ˜์ ์ธ ๋กœ์ง์„ ํ‘œ์ค€ํ™” ํ•œ ๊ฒƒ์ด ๋ฐ”๋กœ Bean Validation ์ž…๋‹ˆ๋‹ค.

 

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” Bean Validation ํ‘œ์ค€ ๊ธฐ์ˆ ์„ ์ด์šฉํ•ด ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ๊ฒ€์ฆ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

( ์—„๋ฐ€ํžˆ ๋งํ•˜๋ฉด Bean Validation ํ‘œ์ค€ ๊ธฐ์ˆ ์˜ ๊ตฌํ˜„์ฒด์ธ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์˜ˆ์ • )

 

์„ค์ •

Bean Validation ์˜์กด๊ด€๊ณ„ ์ถ”๊ฐ€ - build.gradle - dependencies

implementation 'org.springframework.boot:spring-boot-starter-validation'

ํ•˜์ด๋ฒ„๋„ค์ดํŠธ์—์„œ ์ง€์›ํ•˜๋Š” ๊ฒ€์ฆ ์–ด๋…ธํ…Œ์ด์…˜

  • @NotBlank, @NotNull, @Max, @Range ๋“ฑ๋“ฑ..
  • ์•„๋ž˜ ๋งํฌ๋ฅผ ํ†ตํ•ด ์ถ”๊ฐ€์ ์ธ ์–ด๋…ธํ…Œ์ด์…˜๋“ค์„ ๋” ์ฐธ๊ณ ํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Bean Validation ์ ์šฉ

๊ตฌํ˜„ํ–ˆ๋˜ ๊ฒ€์ฆ๋กœ์ง์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  Bean Validation์˜ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ ์šฉํ•ด์„œ ์ƒํ’ˆ๊ด€๋ฆฌ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฒ€์ฆ์ฒ˜๋ฆฌ๋ฅผ ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

Bean Validation์€ ์šฐ์„  ๋„๋ฉ”์ธ์— ์ ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@Data
public class Item {

    private Long id;
    
    @NotBlank
    private String itemName;
    @NotNull
    @Range(min=1000,max=1000000)
    private Integer price;

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

    public Item() {}

    public Item(String itemName, Integer price, Integer quantity) {
        this.itemName = itemName;
        this.price = price;
        this.quantity = quantity;
    }
}
  • @NotBlank : ๋นˆ ์นธ, ๊ณต๋ฐฑ ํ—ˆ์šฉ X
  • @NotNull : null์„ ํ—ˆ์šฉ X
  • @Range(min,max) : min~max ๋ฒ”์œ„ ์•ˆ์˜ ๊ฐ’์ด์–ด์•ผ ํ•จ.
  • @Max(value) : ์ตœ๋Œ€ value ๊ฐ’ ๊นŒ์ง€๋งŒ ํ—ˆ์šฉ.

 

์ด๋ ‡๊ฒŒ ๊ฒ€์ฆ๋กœ์ง์„ ๋„๋ฉ”์ธ์— ๊ฑธ์–ด์ฃผ๋ฉด ์Šคํ”„๋ง์€ ValidationFactory๋กœ ๋ถ€ํ„ฐ Validator(๊ฒ€์ฆ๊ธฐ)๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์„œ ๊ฒ€์ฆ ๋Œ€์ƒ์„ ์ง์ ‘ ๊ฒ€์ฆ๊ธฐ์— ๋„ฃ๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค. ๊ทธ ๊ฒฐ๊ณผ๋Š” ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ BindingResult์— ๋‹ด๊น๋‹ˆ๋‹ค.

 

์ด์ œ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ˆ˜์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

@PostMapping("/add")
public String addItem(@Validated @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes)
{

 

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ฒ€์ฆ ๋Œ€์ƒ์ธ @ModelAttribute Item item์— @Validated ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™ํ˜€ ์ฃผ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ( Validator๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์›๋ฆฌ์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. )

 

๊ฒ€์ฆ ์ˆœ์„œ๋Š” ์ด๋ ‡๊ฒŒ ํ˜๋Ÿฌ๊ฐ‘๋‹ˆ๋‹ค.

 

์šฐ์„  @ModelAttribute ๊ฐ๊ฐ์˜ ํ•„๋“œ์— ํƒ€์ž… ๋ณ€ํ™˜์„ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค.

โ–ถ๏ธŽ ํƒ€์ž…๋ณ€ํ™˜ ์‹คํŒจ์‹œ typeMistmatch๋กœ FieldError ์ถ”๊ฐ€

โ–ถ๏ธŽ ํƒ€์ž… ๋ณ€ํ™˜ ์„ฑ๊ณต ์‹œ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜ Validator ์ ์šฉํ•˜์—ฌ ๊ฒ€์ฆ ๊ณผ์ •์„ ๊ฑฐ์ณ ์˜ค๋ฅ˜ ๋ฐœ์ƒ์‹œ FieldError ์ถ”๊ฐ€

(์ด ๋•Œ ์—๋Ÿฌ์ฝ”๋“œ๋Š” ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค)

ex) @NotNull์˜ ๊ฒฝ์šฐ itemName์—์„œ ํ•„๋“œ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ NotNull.item.itemName, NotNull.itemName, NotNull.java.lang.String, NotNull 

 

 

Bean Validation์€ ๋ฐ”์ธ๋”ฉ์— ์‹คํŒจ( ํƒ€์ž… ๋ณ€ํ™˜ ์‹คํŒจ )ํ•œ ํ•„๋“œ๋Š” Bean Validation์„ ์ ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋ฐ”์ธ๋”ฉ์— ์‹คํŒจํ•ด๋ด์•ผ Bean Validation์„ ์ ์šฉํ•˜๋Š”๊ฒŒ ์˜๋ฏธ๊ฐ€ ์—†๊ธฐ ๋–„๋ฌธ์— ์–ด์ฉŒ๋ฉด ๋‹น์—ฐํ•œ ์–˜๊ธฐ.

 

Bean-Validation ๊ฒ€์ฆ๋„ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณ„๋„์˜ ํŒŒ์ผ์„ ํ†ตํ•ด ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

NotBlank={0} ๊ณต๋ฐฑX
Range={0} {2} ~ {1} ํ—ˆ์šฉ
Max={0}, ์ตœ๋Œ€ {1}

{0} : ํ•„๋“œ๋ช…์ด ์ฃผ์ž…๋ฉ๋‹ˆ๋‹ค.

{1}, {2} .. : ์–ด๋…ธํ…Œ์ด์…˜ ๋งˆ๋‹ค ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์œ„์— ์˜ฌ๋ฆฐ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”. 

 

๋ฉ”์‹œ์ง€๋Š” ์•„๋ž˜ ์šฐ์„ ์ˆœ์œ„๋Œ€๋กœ ๊ธฐ์ž…๋ฉ๋‹ˆ๋‹ค.

  1. messageSource - ์ˆ˜๋™ ๋นˆ, ์ž๋™ ๋นˆ (๋ฉ”์‹œ์ง€ ํŒŒ์ผ) 
  2. ์–ด๋…ธํ…Œ์ด์…˜์˜ message ์†์„ฑ ex) @NotBlank(message = "ํ•„์ˆ˜ ์ž…๋ ฅ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค")
  3. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ ๊ฐ’ ์‚ฌ์šฉ 

Bean Validation - ObjectError ์ฒ˜๋ฆฌ

FieldError๋Š” ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€ ํ™•์‹คํžˆ ์•Œ์•˜๋Š”๋ฐ ๊ทธ๋ ‡๋‹ค๋ฉด ObjectError๋Š” Bean-Validation์—์„œ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ๊นŒ์š”?

Bean-Validation๋ฅผ ์‚ฌ์šฉํ•ด ObjectError๋˜ํ•œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋ฐ”๋กœ @ScriptAssert()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

@Data
@ScriptAssert(lang="javascript", script="_this.price * _this.quantity >= 10000", message="์ˆ˜๋Ÿ‰ * ๊ฐœ์ˆ˜ >= 10000 ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.")
public class Item {

 

ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•ด๋ณด๋ฉด ํ•œ๊ณ„๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ๊ฐ์ฒด์˜ ๋ฒ”์œ„๋ฅผ ๋„˜์–ด์„œ๋Š” ๊ฒฝ์šฐ์—๋Š” ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋‹ค๋˜์ง€.. ๋“ฑ ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ๋Œ€์‘์ด ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ถŒ์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋‹™๋‹ˆ๋‹ค.

 

ObjectError์— ํ•œํ•ด์„œ๋Š” ๊ทธ๋ƒฅ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋‹ค๋ฃจ๋Š”๊ฒŒ ๊ฐ€์žฅ ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ObjectError๋Š” ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋กœ์ง์„ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์„œ bindingresult์— ๋‹ด๋Š” ๋ฐฉํ–ฅ์„ ์ง€ํ–ฅํ•ฉ์‹œ๋‹ค.


Bean Validation - ๊ทธ๋ฃนํ™” (groups)

Bean Validation์€ ๋„๋ฉ”์ธ์— ์ง์ ‘ ๊ฒ€์ฆ์„ ๊ฑธ์–ด์ฃผ๋Š” ํ˜•ํƒœ๋ผ ์œ ์—ฐํ•˜๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ด๊ฒŒ ๋ฌด์Šจ ๋ง์ด๋ƒ๋ฉด ์˜ˆ๋ฅผ๋“ค์–ด ์ƒํ’ˆ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์—์„œ ๋“ฑ๋กํ•  ๋•Œ์—๋Š” ์ˆ˜๋Ÿ‰์„ ์ตœ๋Œ€ 10000๊ฐœ๋กœ, ์ˆ˜์ •ํ•  ๋–„์—๋Š” ์ˆ˜๋Ÿ‰์„ ์ตœ๋Œ€ 50000๊ฐœ๋กœ ์„ค์ •ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋“ฑ๋ก์—์„œ๋„ ์ˆ˜์ •์—์„œ๋„ ๊ฐ™์€ ๋„๋ฉ”์ธ์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ด์—์š”. 

 

์ด๋Ÿด ๋•Œ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ๊ทธ๋ฃนํ™”์ž…๋‹ˆ๋‹ค.

 

Bean validation์˜ groups ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด์„œ ๋“ฑ๋ก๊ฒ€์ฆ, ์ˆ˜์ •๊ฒ€์ฆ์„ ๊ทธ๋ฃน์œผ๋กœ ๋‚˜๋ˆ„์–ด ์ ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”.

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

 

@Validated์—๋„ ์ด๋ ‡๊ฒŒ ๊ทธ๋ฃน์„ ์„ค์ •ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜ : @Valid์—๋Š” groups ์˜ต์…˜์„ ์ ์šฉํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— groups์„ ์“ฐ๊ณ ์ž ํ•œ๋‹ค๋ฉด @Validated๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
@PostMapping("/add")
public String addItem2(@Validated(SaveCheck.class) @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes)
@PostMapping("/{itemId}/edit")
public String edit(@PathVariable Long itemId, @Validated(UpdateCheck.class) @ModelAttribute Item item, BindingResult bindingResult)

 

groups์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ ˆ๋ฒจ์ด ๋†’์•„์งˆ์ˆ˜๋ก ๋ณต์žกํ•˜๊ณ  ์ฝ๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ์‹ค๋ฌด์—์„œ๋Š” groups๋ฅผ ์ž˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ ์ด๋Ÿฐ ๊ธฐ๋Šฅ์ด ์žˆ๊ตฌ๋‚˜ ์ •๋„๋กœ ์•Œ์•„๋‘๊ณ  ๋„˜์–ด๊ฐ€๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


์ „์†ก ๊ฐ์ฒด ๋ถ„๋ฆฌ ํ›„ Bean Validation ์ ์šฉ

์ง€๊ธˆ๊นŒ์ง€๋Š” ๋“ฑ๋กํ•  ๋•Œ๋‚˜ ์ˆ˜์ •ํ•  ๋•Œ๋‚˜ ํผ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์— Item ๋„๋ฉ”์ธ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ด์„œ

HTML Form  โžฃ Item โžฃ Controller โžฃ Item โžฃ Repository ์ด๋Ÿฐ ํ”Œ๋กœ์šฐ๋กœ ๋™์ผํ•˜๊ฒŒ ํ˜๋Ÿฌ๊ฐ”์—ˆ์Šต๋‹ˆ๋‹ค.

 

์ด๋ ‡๊ฒŒ Item ๋„๋ฉ”์ธ์œผ๋กœ ํ‰์ณ์„œ ๊ฒ€์ฆํ•˜๋ฉด ์œ ์—ฐํ•˜๊ฒŒ ๊ฒ€์ฆ์„ ์„ค์ •ํ•  ์ˆ˜ ์—†๊ณ , groups๋ผ๋Š” ๊ท€์ฐฎ์€ ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

์‹ค๋ฌด์—์„œ๋Š” ํผ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์„ ์œ„ํ•œ ๊ฐ์ฒด๋ฅผ ๋ณ„๋„๋กœ ์ง€์ •ํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • ์ƒํ’ˆ ๊ด€๋ฆฌ๋ฅผ ์˜ˆ๋กœ๋“ ๋‹ค๋ฉด ๋“ฑ๋ก ํผ ๊ฐ์ฒด(ItemSaveForm), ์ˆ˜์ • ํผ ๊ฐ์ฒด(ItemUpdateForm) ์ด๋ ‡๊ฒŒ.
  • ์ปจํŠธ๋กค๋Ÿฌ์—์„œ๋Š” ํผ ๊ฐ์ฒด์˜ ๋ฐ์ดํ„ฐ ๊ธฐ๋ฐ˜์œผ๋กœ Item ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ์ถ”๊ฐ€๊ณผ์ •์ด ์žˆ์ง€๋งŒ ๊ฒ€์ฆ์ด ์ค‘๋ณต๋˜์ง€ ์•Š๊ณ , ์ฝ๊ธฐ๋„ ํ›จ์”ฌ ์‰ฌ์›Œ์กŒ์–ด์š”. ์ด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฑธ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ๋“ฑ๋ก์€ HTML Form โžฃ ItemSaveForm โžฃ Controller โžฃ Item ์ƒ์„ฑ โžฃ Repository
  • ์ˆ˜์ •์€ HTML Form โžฃ ItemUpdateForm โžฃ Controller โžฃ Item ์ƒ์„ฑ โžฃ Repository 
ํผ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์„ ํ•˜๋ฉด Item ๋„๋ฉ”์ธ์—๋Š” ๊ฒ€์ฆ์„ ๊ฑธ์–ด์ค„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
๊ฒ€์ฆ์€ Form ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ๋ณ„๋„๋กœ ์ง€์ •.

ItemSaveForm / ItemUpdateForm

์ปจํŠธ๋กค๋Ÿฌ์—๋„ ์ ์šฉ์„ ํ–ˆ์„ ๋•Œ ๋“ฑ๋ก์˜ ๊ฒฝ์šฐ

@PostMapping("/add")
public String addItem(@Validated @ModelAttribute("item") ItemSaveForm form, BindingResult bindingResult,
                      RedirectAttributes redirectAttributes)
{

@ModelAttribute๋กœ addForm์—์„œ POST๋กœ ๋„˜์–ด์˜จ item์„ ItemSaveForm form์— ํ•„๋“œ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค. 

1. @Validated๋กœ ItemSaveForm์— ๊ฒ€์ฆ๋œ ํ•„๋“œ๋งŒ ์ฃผ์ž…๋ฉ๋‹ˆ๋‹ค. ํƒ€์ž… ์˜ค๋ฅ˜ ๋ฐœ์ƒ ํ•˜๋ฉด bindingResult์— ๋‹ด๊ธฐ๊ณ  Bean-Validation ์ ์šฉ X
2. @ModelAttribute("item") ์œผ๋กœ ์„ค์ •ํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜์ง€ ์•Š์œผ๋ฉด Model์— itemSaveForm๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๋‹ด๊ธฐ๊ธฐ ๋•Œ๋ฌธ์—, ๋ทฐ ํ…œํ”Œ๋ฆฟ์—์„œ ์ ‘๊ทผํ•˜๋Š” th:object๋„ itemSaveForm์œผ๋กœ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
if (form.getPrice() != null && form.getQuantity() != null)
{
    int resultPrice = form.getPrice() * form.getQuantity();
    if (resultPrice < 10000) {
        bindingResult.reject("totalPriceMin", new Object[]{10000, resultPrice}, null);
    }
}

ObjectError๋Š” Item ๋„๋ฉ”์ธ์˜ ํ•„๋“œ๊ฐ€ ์•„๋‹Œ form์˜ ํ•„๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜๋„๋ก ๋ณ€๊ฒฝ.

Item item = new Item(form.getItemName(),form.getPrice(),form.getQuantity());
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("status",true);
redirectAttributes.addAttribute("itemId",savedItem.getId());

 Repository์—๋Š” item์ด ๊ธฐ๋ก๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.  ๋”ฐ๋ผ์„œ form ๊ฐ์ฒด์˜ ํ•„๋“œ ๊ธฐ๋ฐ˜์œผ๋กœ item์„ ๋งŒ๋“ค๊ณ  ๋„ฃ์–ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. 

 

์ˆ˜์ •์˜ ๊ฒฝ์šฐ๋„ ๊ฐ™์€ ๋งฅ๋ฝ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ๊ณผ์ •์„ ์„ค๋ช…ํ•˜๋Š” ๊ฑด ์ƒ๋žตํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 


Bean Validation - @Validated @RequestBody 

@Valid @Validated๋Š” @ModelAttribute ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ @RequestBody(HttpMessageConverter)์—๋„ ์ ์šฉ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

@ModelAttribute๋Š” HTTP ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ(URL ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์ด๋‚˜ POST Form)๋ฅผ ๋‹ค๋ฃฐ ๋•Œ ์‚ฌ์šฉ. 
@RequestBody๋ฅผ ์‚ฌ์šฉํ•ด Http Body์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ ์‚ฌ์šฉ.

 

@ModelAttribute์—์„œ๋Š” ๊ฐ๊ฐ์˜ ํ•„๋“œ ๋‹จ์œ„๋กœ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์— ํŠน์ • ํ•„๋“œ์— ํƒ€์ž…์ด ๋งž์ง€ ์•Š๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ๋‚˜๋จธ์ง€ ํ•„๋“œ๋Š” ์ •์ƒ ์ฒ˜๋ฆฌ ๋˜์–ด ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

  • ๊ฒ€์ฆ ์„ฑ๊ณต์˜ ๊ฒฝ์šฐ๋Š” ๋‹น์—ฐํžˆ ๊ฐ์ฒด ์ƒ์„ฑ ์„ฑ๊ณต & ์ปจํŠธ๋กค๋Ÿฌ ํ˜ธ์ถœ
  • ํƒ€์ž… ์˜ค๋ฅ˜ ๋ฐœ์ƒ์˜ ๊ฒฝ์šฐ ๊ฐ์ฒด ์ƒ์„ฑ์— ์„ฑ๊ณต (์˜ค๋ฅ˜ ๋ฐœ์ƒ ํ•„๋“œ๋ฅผ ์ œ์™ธํ•œ ๊ฐ’๋“ค์€ ์ฃผ์ž…๋œ ์ƒํƒœ๋กœ)ํ•˜๊ณ  ์ปจํŠธ๋กค๋Ÿฌ ๋˜ํ•œ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  • ํ•„๋“œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ์˜ ๊ฒฝ์šฐ์—๋Š” ๊ฐ์ฒด ์ƒ์„ฑํ•˜๊ณ , ์ปจํŠธ๋กค๋Ÿฌ ํ˜ธ์ถœํ–ˆ์Šต๋‹ˆ๋‹ค.

 

๋ฐ˜๋ฉด @RequestBody๋Š” HttpMessageConverter ๋‹จ๊ณ„์—์„œ JSON ๋ฐ์ดํ„ฐ๋กœ ๊ฐ์ฒด๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ๋ชปํ•˜๋ฉด ์ดํ›„ ๋‹จ๊ณ„ ์ž์ฒด๊ฐ€ ์ง„ํ–‰๋˜์ง€ ์•Š๊ณ  ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์ปจํŠธ๋กค๋Ÿฌ๋„ ํ˜ธ์ถœ๋˜์ง€ ์•Š๊ณ , Validator๋„ ์ ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  • ๊ฒ€์ฆ ์„ฑ๊ณต์˜ ๊ฒฝ์šฐ๋Š” ๋‹น์—ฐํžˆ ๊ฐ์ฒด ์ƒ์„ฑ ์„ฑ๊ณต & ์ปจํŠธ๋กค๋Ÿฌ ํ˜ธ์ถœ
  • ํƒ€์ž… ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ์—๋„ MessageConverter์—์„œ ๊ฐ์ฒด ์ƒ์„ฑ ์‹คํŒจํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ปจํŠธ๋กค๋Ÿฌ ๋˜ํ•œ ํ˜ธ์ถœํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.
  • ํ•„๋“œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ์—๋Š” ํƒ€์ž… ์˜ค๋ฅ˜๋Š” ํ†ต๊ณผํ•œ ์ƒํƒœ์ด๋ฏ€๋กœ MessageConverter๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋Š” ์ƒ์„ฑํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  @Validator๊ฐ€ ์ ์šฉ๋˜์–ด ํ•„๋“œ ์˜ค๋ฅ˜๋ฅผ ์žก์•„๋ƒ…๋‹ˆ๋‹ค.

Postman์„ ์ด์šฉํ•ด ํ…Œ์ŠคํŠธ

@Slf4j
@RestController
@RequestMapping("/validation/api/items")
public class ValidationItemApiController {

    @PostMapping("/add")
    public Object addItemRequestBody(@Validated @RequestBody ItemSaveForm form,
                          BindingResult bindingResult)
    {
        log.info("API ์ปจํŠธ๋กค๋Ÿฌ ํ˜ธ์ถœ");
        if(bindingResult.hasErrors())
        {
            log.info("๊ฒ€์ฆ ์˜ค๋ฅ˜ ๋ฐœ์ƒ errors={}", bindingResult);
            log.info("{}",form);
            return bindingResult.getAllErrors();
        }

        return form;
    }
    
    @PostMapping("/add2")
    public Object addItemModelAttribute(@Validated @ModelAttirubte ItemSaveForm form,
                          BindingResult bindingResult)
    {
        log.info("API ์ปจํŠธ๋กค๋Ÿฌ ํ˜ธ์ถœ");
        if(bindingResult.hasErrors())
        {
            log.info("๊ฒ€์ฆ ์˜ค๋ฅ˜ ๋ฐœ์ƒ errors={}", bindingResult);
            log.info("{}",form);
            return bindingResult.getAllErrors();
        }

        return form;
    }
}

<์ฐธ๊ณ ์ž๋ฃŒ>

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard

 

์Šคํ”„๋ง MVC 2ํŽธ - ๋ฐฑ์—”๋“œ ์›น ๊ฐœ๋ฐœ ํ™œ์šฉ ๊ธฐ์ˆ  - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ๋ชจ๋“  ์›น ๊ธฐ์ˆ ์„ ๊ธฐ์ดˆ๋ถ€ํ„ฐ ์ดํ•ดํ•˜๊ณ , ์™„์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. MVC 2ํŽธ์—์„œ๋Š” MVC 1ํŽธ์˜ ํ•ต์‹ฌ ์›๋ฆฌ์™€ ๊ตฌ์กฐ ์œ„์— ์‹ค๋ฌด ์›น ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ๋ชจ๋“  ํ™œ์šฉ ๊ธฐ์ˆ ๋“ค์„ ํ•™์Šตํ•  ์ˆ˜ ์žˆ

www.inflearn.com

 

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

Study Repository

rlaehddnd0422

ํ™œ๋™ํ•˜๊ธฐ