# ๊ฒ€์ฆ(Validation) ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•
Study Repository

๊ฒ€์ฆ(Validation) ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•

by rlaehddnd0422

๊ฒ€์ฆ ์š”๊ตฌ์‚ฌํ•ญ 

์ƒํ’ˆ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์—์„œ ์ƒํ’ˆ ๋“ฑ๋ก ํผ์˜ ์ž…๋ ฅ๊ฐ’์— ๋Œ€ํ•œ ๊ฒ€์ฆ ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

ํƒ€์ž… ๊ฒ€์ฆ : ๊ฐ€๊ฒฉ, ์ˆ˜๋Ÿ‰์— ๋ฌธ์ž๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ๊ฒ€์ฆ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ

 

ํ•„๋“œ ๊ฒ€์ฆ 

  • ์ƒํ’ˆ๋ช… : ํ•„์ˆ˜, ๊ณต๋ฐฑ X
  • ๊ฐ€๊ฒฉ : 1000์›~1๋ฐฑ๋งŒ์› ์ดํ•˜
  • ์ˆ˜๋Ÿ‰ : ์ตœ๋Œ€ 9999

ํŠน์ • ํ•„๋“œ์˜ ๋ฒ”์œ„๋ฅผ ๋„˜์–ด์„œ๋Š” ๊ฒ€์ฆ

  • ๊ฐ€๊ฒฉ*์ˆ˜๋Ÿ‰ >= 10000์›

  • ์ปจํŠธ๋กค๋Ÿฌ์˜ ์ค‘์š”ํ•œ ์—ญํ•  ์ค‘ ํ•˜๋‚˜๋Š” HTTP ์š”์ฒญ์ด ์ •์ƒ์ธ์ง€ ๊ฒ€์ฆํ•˜๋Š” ์ผ์ž…๋‹ˆ๋‹ค. 
  • ๊ฒ€์ฆ์—๋Š” ํด๋ผ์ด์–ธํŠธ ๊ฒ€์ฆ, ์„œ๋ฒ„ ๊ฒ€์ฆ์ด ์žˆ๋Š”๋ฐ ํด๋ผ์ด์–ธํŠธ ๊ฒ€์ฆ์€ ์กฐ์ž‘์ด ๊ฐ€๋Šฅํ•ด์„œ ๋ณด์•ˆ์— ์ทจ์•ฝํ•˜๊ณ ,
  • ์„œ๋ฒ„๋งŒ์œผ๋กœ ๊ฒ€์ฆํ•˜๋ฉด, ์ฆ‰๊ฐ์ ์ธ ๊ณ ๊ฐ ์‚ฌ์šฉ์„ฑ์ด ๋ถ€์กฑํ•ด์ง‘๋‹ˆ๋‹ค.
  • ๋‘˜์„ ์ ์ ˆํžˆ ์‚ฌ์šฉํ•˜๋˜, ์ตœ์ข…์ ์ธ ์„œ๋ฒ„๊ฒ€์ฆ์€ ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค.
  • API ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด API ์ŠคํŽ™์„ ์ž˜ ์ •์˜ํ•ด์„œ ๊ฒ€์ฆ ์˜ค๋ฅ˜๋ฅผ API ์‘๋‹ต ๊ฒฐ๊ณผ์— ์ž˜ ๋‚จ๊ฒจ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ฒ€์ฆ ์‹คํŒจ ๊ณผ์ •

 @PostMapping("/add")์—์„œ ์ƒํ’ˆ ์ €์žฅ์— ์‹คํŒจํ•˜๋ฉด Model์— ๊ฒ€์ฆ ์˜ค๋ฅ˜ ๊ฒฐ๊ณผ๋ฅผ ํฌํ•จํ•ด์„œ ์ƒํ’ˆ ๋“ฑ๋ก ํผ์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ํ•ด์ค๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ๊ฒ€์ฆ์— ์‹คํŒจํ–ˆ์„ ๋•Œ, ๋‹ค์‹œ ์ƒํ’ˆ ๋“ฑ๋ก ํผ์„ ๋ณด์—ฌ์ฃผ๊ณ , ์˜ค๋ฅ˜ ๊ฒฐ๊ณผ๋ฅผ ํ†ตํ•ด ์–ด๋–ค ๊ฐ’์„ ์ž˜๋ชป์ž…๋ ฅํ–ˆ๋Š”์ง€ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.

 

์ด์ œ ๊ฒ€์ฆ ๋กœ์ง์„ ์ง์ ‘ ๊ฐœ๋ฐœํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


๊ฒ€์ฆ ์ฒ˜๋ฆฌ - ์ง์ ‘ ๊ฐœ๋ฐœ using Map

Controller

@PostMapping("/add")
public String addItem(@ModelAttribute Item item, RedirectAttributes redirectAttributes,
                      Model model) {

    // ๊ฒ€์ฆ ์˜ค๋ฅ˜ ๊ฒฐ๊ณผ ๋ณด๊ด€
    Map<String,String> errors = new HashMap<>();


    // ๊ฒ€์ฆ ๋กœ์ง - ์ƒํ’ˆ๋ช…
    if(!StringUtils.hasText(item.getItemName()))
    {
        errors.put("itemName","์ƒํ’ˆ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.");
    }

    // ๊ฒ€์ฆ ๋กœ์ง - ๊ฐ€๊ฒฉ
    if(item.getPrice()==null || item.getPrice()<1000 || item.getPrice() > 1000000)
    {
        errors.put("price","๊ฐ€๊ฒฉ์€ 1,000 ~ 1,000,000์›๊นŒ์ง€ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.");
    }

    // ๊ฒ€์ฆ ๋กœ์ง - ์ˆ˜๋Ÿ‰
    if(item.getQuantity() == null || item.getQuantity() >= 9999)
    {
        errors.put("quantity","์ˆ˜๋Ÿ‰์€ ์ตœ๋Œ€ 9999๊นŒ์ง€ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.");
    }

    // ๋ณตํ•ฉ ๋กœ์ง - ๊ฐ€๊ฒฉ*์ˆ˜๋Ÿ‰
    if(item.getPrice() != null && item.getItemName()!=null)
    {
        int resultPrice = item.getPrice() * item.getQuantity();
        if(resultPrice<10000)
        {
            errors.put("globalError","๊ฐ€๊ฒฉ * ์ˆ˜๋Ÿ‰์˜ ํ•ฉ์€ 10,000์› ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. " +
                    "ํ˜„์žฌ ๊ฐ’ = " + resultPrice + "์›");
        }
    }

    if(!errors.isEmpty())
    {
        log.info("Error message = {}",errors);
        model.addAttribute("errors",errors);
        return "validation/v1/addForm";
    }

    // ์„ฑ๊ณต ๋กœ์ง
    Item savedItem = itemRepository.save(item);
    redirectAttributes.addAttribute("itemId", savedItem.getId());
    redirectAttributes.addAttribute("status", true);
    return "redirect:/validation/v1/items/{itemId}";
}

Logic

@PostMapping("/add")
public String addItem(@ModelAttribute Item item, RedirectAttributes redirectAttributes,
                      Model model) {
  • Postํ•  ๋•Œ ๋งคํ•‘๋œ ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ธฐ๋ฐ˜์œผ๋กœ @ModelAttribute Item item ์ƒ์„ฑ
  • โ–ถ๏ธŽ item์˜ property ์ฐพ์•„ setter ์ฃผ์ž… ( ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์ž๋™ํ™” )
// ๊ฒ€์ฆ ์˜ค๋ฅ˜ ๊ฒฐ๊ณผ ๋ณด๊ด€
Map<String,String> errors = new HashMap<>();
  • HashMap<String,value>์— ๊ฒ€์ฆ ์˜ค๋ฅ˜ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ด€ํ•ฉ๋‹ˆ๋‹ค.
  • <key,value> = < ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ํ•„๋“œ๋ช…, ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ >
// ๊ฒ€์ฆ ๋กœ์ง - ์ƒํ’ˆ๋ช…
if(!StringUtils.hasText(item.getItemName()))
{
    errors.put("itemName","์ƒํ’ˆ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.");
}

// ๊ฒ€์ฆ ๋กœ์ง - ๊ฐ€๊ฒฉ
if(item.getPrice()==null || item.getPrice()<1000 || item.getPrice() > 1000000)
{
    errors.put("price","๊ฐ€๊ฒฉ์€ 1,000 ~ 1,000,000์›๊นŒ์ง€ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.");
}

// ๊ฒ€์ฆ ๋กœ์ง - ์ˆ˜๋Ÿ‰
if(item.getQuantity() == null || item.getQuantity() >= 9999)
{
    errors.put("quantity","์ˆ˜๋Ÿ‰์€ ์ตœ๋Œ€ 9999๊นŒ์ง€ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.");
}

// ๋ณตํ•ฉ ๋กœ์ง - ๊ฐ€๊ฒฉ*์ˆ˜๋Ÿ‰
if(item.getPrice() != null && item.getItemName()!=null)
{
    int resultPrice = item.getPrice() * item.getQuantity();
    if(resultPrice<10000)
    {
        errors.put("globalError","๊ฐ€๊ฒฉ * ์ˆ˜๋Ÿ‰์˜ ํ•ฉ์€ 10,000์› ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. " +
                "ํ˜„์žฌ ๊ฐ’ = " + resultPrice + "์›");
    }
}

 

1. ๊ฒ€์ฆ ๋กœ์ง - ์ƒํ’ˆ๋ช…

  • item ๊ฐ์ฒด์˜ Name์ด ๋น„์–ด์žˆ์„ ๊ฒฝ์šฐ ๋งต์— itemName (= ์˜ค๋ฅ˜๋ฐœ์ƒ ํ•„๋“œ๋ช…), ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ put

2. ๊ฒ€์ฆ ๋กœ์ง - ๊ฐ€๊ฒฉ

  • item ๊ฐ์ฒด์˜ ๊ฐ€๊ฒฉ == null || <1000 || > 1000000 ์ด๋ฉด ๋งต์— price, ์˜ค๋ฅ˜๋ฉ”์‹œ์ง€ put

3. ๊ฒ€์ฆ ๋กœ์ง - ๊ฐ€๊ฒฉ

  • item ๊ฐ์ฒด์˜ ์ˆ˜๋Ÿ‰ == null || >= 9999 ๋ฉด ๋งต์— quantity, ์˜ค๋ฅ˜๋ฉ”์‹œ์ง€ put

4. ๋ณตํ•ฉ ๋กœ์ง - ๊ฐ€๊ฒฉ*์ˆ˜๋Ÿ‰

  • item ๊ฐ์ฒด์˜ ๊ฐ€๊ฒฉ*์ˆ˜๋Ÿ‰ < 10000 ์ด๋ฉด ๋งต์— globalError, ์˜ค๋ฅ˜๋ฉ”์‹œ์ง€ put
if(!errors.isEmpty())
{
    log.info("Error message = {}",errors);
    model.addAttribute("errors",errors);
    return "validation/v1/addForm";
}

// ์„ฑ๊ณต ๋กœ์ง
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("itemId", savedItem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/validation/v1/items/{itemId}";

๊ฒ€์ฆ ๊ณผ์ •(์‹คํŒจ) 

์—๋Ÿฌ ๋งต์ด ๋น„์–ด์žˆ์ง€ ์•Š์œผ๋ฉด ์ฆ‰, ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•ด

model์— errors(์—๋Ÿฌ ์ •๋ณด๊ฐ€ ๋‹ด๊ธด ๋งต)์„ ๋‹ด์•„ addForm ๋ทฐ ํ…œํ”Œ๋ฆฟ์„ ์žฌ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

( addForm์—๋Š” ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•œ ์š”์†Œ๋ฅผ ์ถ”๊ฐ€์ ์œผ๋กœ ์„ค์ •ํ•ด ์ฃผ์–ด์•ผ ๊ฒ ์ฃ ? )

 

๊ฒ€์ฆ ๊ณผ์ •(์„ฑ๊ณต)

์„ฑ๊ณต ๋กœ์ง ์‹คํ–‰ ( repository ์ €์žฅ -> redirectAttribute์— itemId์™€ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ status=true ์„ค์ • -> ์•„์ดํ…œ ์ƒ์„ธ ํผ์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰์…˜ )

 

addForm.html

<style>
    .container {
        max-width: 560px;
    }
    .field-error {
        border-color: #dc3545;
        color: #dc3545;
    }
</style>

์šฐ์„  class='field-error'๋กœ ์ง€์ •๋œ ๊ฒฝ์šฐ ์ƒ‰๊น”์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด style ํƒœ๊ทธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•ด์ฃผ์—ˆ์–ด์š”.

<div th:if="${errors?.containsKey('globalError')}">
    <p class="field-error" th:text="${errors['globalError']}">
    ๊ธ€๋กœ๋ฒŒ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€</p>
</div>

์šฐ์„  ๊ธ€๋กœ๋ฒŒ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ถ€ํ„ฐ ์ฒ˜๋ฆฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 th:if ๋ฌธ์„ ์ด์šฉํ•ด errors ๋งต์ด 'globalError'์„ ๊ฐ–๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์žˆ๋‹ค๋ฉด ํ•˜์œ„ํƒœ๊ทธ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์—†๋‹ค๋ฉด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

โ—๏ธerrors ๋’ค์— ?๋ฅผ ๋ถ™์ธ errors?. ์€ errors๊ฐ€ null์ธ ๊ฒฝ์šฐ NPE(NullPointerException)์„ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š๊ณ  null์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฌธ๋ฒ•์ž…๋‹ˆ๋‹ค. th:if์—์„œ null์€ ์‹คํŒจ๋กœ ์ฒ˜๋ฆฌ๋˜๋ฏ€๋กœ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
<div>
    <label for="itemName" th:text="#{label.item.itemName}">์ƒํ’ˆ๋ช…</label>
    <input type="text" id="itemName" th:field="*{itemName}"
           th:class=" ${errors?.containsKey('itemName')} ? 'form-control field-error' : 'form-control' "
           class="form-control" placeholder="์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”">
    <div class="field-error" th:if="${errors?.containsKey('itemName')}" th:text="${errors['itemName']}"></div>
</div>
<div>
    <label for="price" th:text="#{label.item.price}">๊ฐ€๊ฒฉ</label>
    <input type="text" id="price" th:field="*{price}"
           th:classappend=" ${errors?.containsKey('price')} ? 'field-error' : _"
           class="form-control" placeholder="๊ฐ€๊ฒฉ์„ ์ž…๋ ฅํ•˜์„ธ์š”">
    <div class="field-error" th:if="${errors?.containsKey('price')}" th:text="${errors['price']}"></div>

</div>

<div>
    <label for="quantity" th:text="#{label.item.quantity}">์ˆ˜๋Ÿ‰</label>
    <input type="text" id="quantity" th:field="*{quantity}" class="form-control"
           th:class=" ${errors?.containsKey('quantity')} ? 'form-control field-error' : 'form-control' "
           placeholder="์ˆ˜๋Ÿ‰์„ ์ž…๋ ฅํ•˜์„ธ์š”">
    <div class="field-error" th:if="${errors?.containsKey('quantity')}" th:text="${errors['quantity']}"></div>

</div>

์ด์ œ ํ•„๋“œ ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

  • ํ•„๋“œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ - th:class (์ž…๋ ฅ ํผ ์ƒ‰์ƒ ์ ์šฉ)
    • th:class๋ฅผ ํ†ตํ•ด errors ๋งต์— 'itemName'์˜ ํ•„๋“œ ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์žˆ์œผ๋ฉด class๋ฅผ 'form-control', 'field-error'๋กœ ์„ค์ •ํ•˜๊ณ  ์—†์œผ๋ฉด 'form-control'๋กœ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
    • th:classappend๋ฅผ ํ†ตํ•ด ์ฒ˜๋ฆฌํ• ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค ( price๋Š” th:classappend ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์—๋Ÿฌ๋งต์— 'price' key๊ฐ€ ์žˆ์œผ๋ฉด field-error ํด๋ž˜์Šค๋ฅผ append )
  • ํ•„๋“œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ - ๋ฉ”์‹œ์ง€
    • ํ•„๋“œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ th:if๋ฅผ ์‚ฌ์šฉํ•ด ํ•ด๋‹น ํ•„๋“œ ํ‚ค๊ฐ€ ์žˆ์œผ๋ฉด ํ‚ค์— ๋Œ€ํ•œ value๋ฅผ ์ถœ๋ ฅํ•˜๋„๋ก ์„ค์ •

 

์ง์ ‘ ๊ฐœ๋ฐœํ•œ ๊ฒ€์ฆ ์ฒ˜๋ฆฌ

  • ๊ฒ€์ฆ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ž…๋ ฅํผ(addForm)์„ ๋‹ค์‹œ ๋ณด์—ฌ์ฃผ๋„๋ก ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฒ€์ฆ ์˜ค๋ฅ˜ ๋ฐœ์ƒ์‹œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋“ค์„ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ํ‘œ์‹œํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฒ€์ฆ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ๊ณ ๊ฐ์ด ์ž…๋ ฅํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ทธ๋Œ€๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. How?

 

@GetMapping("/add")
public String addForm(Model model) {
    model.addAttribute("item", new Item());
    return "validation/v1/addForm";
}

์ตœ์ดˆ ์ƒํ’ˆ๋“ฑ๋ก ํผ ์š”์ฒญ ์‹œ Item์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ค์ •ํ•˜์ง€ ์•Š๊ณ  ๋ชจ๋ธ์— ๋‹ด์•„์ฃผ์–ด addForm์œผ๋กœ ๋„˜๊ฒจ์ฃผ์—ˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

@PostMapping("/add")
public String addItem(@ModelAttribute Item item, RedirectAttributes redirectAttributes,
                      Model model) {
<input type="text" id="itemName" th:field="*{itemName}"
<input type="text" id="price" th:field="*{price}"

๊ฒ€์ฆ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ addForm์—์„œ @ModelAttribute Item item์— ํ”„๋กœํผํ‹ฐ ์ฃผ์ž…๋œ ๊ฐ’๋“ค์„ addForm์—์„œ ํ•„๋“œ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฒ€์ฆ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ๊ณ ๊ฐ์ด ์ž…๋ ฅํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ทธ๋Œ€๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

 

๋‚จ์€ ๋ฌธ์ œ์ 

  • ๋ทฐํ…œํ”Œ๋ฆฟ์—์„œ์˜ ์ค‘๋ณต์ฒ˜๋ฆฌ๊ฐ€ ๋งŽ์Œ.
  • ํƒ€์ž… ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ 
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํƒ€์ž… ์˜ค๋ฅ˜๊ฐ’ ์ž…๋ ฅ ์‹œ ( ex) price์— ๋ฌธ์ž์ž…๋ ฅ ) ์ž…๋ ฅํ•œ ๊ฐ’ ๋ณ„๋„ ๊ด€๋ฆฌ ํ•„์š”

BindingResult๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒ€์ฆ ์ฒ˜๋ฆฌ

์ง€๊ธˆ๋ถ€ํ„ฐ๋Š” ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ๊ฒ€์ฆ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. 

Controller

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

    // ๊ฒ€์ฆ ๋กœ์ง - ์ƒํ’ˆ๋ช…
    if(!StringUtils.hasText(item.getItemName()))
    {
        bindingResult.addError(new FieldError("item","itemName","์ƒํ’ˆ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."));
    }

    // ๊ฒ€์ฆ ๋กœ์ง - ๊ฐ€๊ฒฉ
    if(item.getPrice()==null || item.getPrice()<1000 || item.getPrice() > 1000000)
    {
        bindingResult.addError(new FieldError("item","price","๊ฐ€๊ฒฉ์€ 1,000 ~ 1,000,000๊นŒ์ง€ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค."));
    }

    // ๊ฒ€์ฆ ๋กœ์ง - ์ˆ˜๋Ÿ‰
    if(item.getQuantity() == null || item.getQuantity() >= 9999)
    {
        bindingResult.addError(new FieldError("item","quantity","์ˆ˜๋Ÿ‰์€ ์ตœ๋Œ€ 9,999๊นŒ์ง€ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค."));
    }

    if(item.getPrice() != null && item.getItemName()!=null)
    {
        int resultPrice = item.getPrice() * item.getQuantity();
        if(resultPrice<10000)
        {
            bindingResult.addError(new ObjectError("item","๊ฐ€๊ฒฉ * ์ˆ˜๋Ÿ‰์˜ ํ•ฉ์€ 10,000์› ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค." +
            "ํ˜„์žฌ ๊ฐ’ = " + resultPrice));
        }
    }

    if(bindingResult.hasErrors())
    {
        log.info("Error message = {}",bindingResult);
        return "validation/v2/addForm";
    }

    // ์„ฑ๊ณต ๋กœ์ง
    Item savedItem = itemRepository.save(item);
    redirectAttributes.addAttribute("itemId", savedItem.getId());
    redirectAttributes.addAttribute("status", true);
    return "redirect:/validation/v2/items/{itemId}";
}

BindingResult๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์‹ค์ œ๋กœ ๋„˜์–ด์˜ค๋Š” ๊ตฌํ˜„์ฒด๋Š” BeanPropertyBindingResult๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. 

๋‹ค์ด์–ด๊ทธ๋žจ

BindingResult๋Œ€์‹  Errors๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋˜์ง€๋งŒ Errors ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋‹จ์ˆœํ•œ ์˜ค๋ฅ˜ ์ €์žฅ๊ณผ ์กฐํšŒ ๊ธฐ๋Šฅ๋งŒ ์ œ๊ณตํ•˜๊ณ , BindingReuslt๋Š” ์—ฌ๊ธฐ์— ๋”ํ•ด์„œ ์ถ”๊ฐ€์ ์ธ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. addError()๋„ BindingResult๊ฐ€ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

addError๋Š” AbstractBindingResult์— ์œ„์™€ ๊ฐ™์ด ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
FieldError๋Š” ObjectError์™€ ์ƒ์†๊ด€๊ณ„์ด๋ฏ€๋กœ FieldError๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ.

๋™์ž‘ ์›๋ฆฌ

@ModelAttribute์— ๊ฒ€์ฆ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ bindingResult์— ํ•„๋“œ ์˜ค๋ฅ˜๋Š” FieldError๋ฅผ, ๊ธ€๋กœ๋ฒŒ ์˜ค๋ฅ˜๋Š” ObjectError๋ฅผ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค. 

+ BindingResult๋Š” Model์— ์ž๋™์œผ๋กœ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

โ—๏ธBindingResult bindingResult์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ„์น˜๋Š” @ModelAttribute Item item ๋‹ค์Œ์— ์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

๊ธ€๋กœ๋ฒŒ ์˜ค๋ฅ˜ - ObjectError

ObjectError parameter

ObjectError์˜ ํŒŒ๋ผ๋ฏธํ„ฐ

  • objectName : @ModelAttribute์˜ ์ด๋ฆ„ 
  • defaultMesage : ์„ค์ •ํ•  ๊ธฐ๋ณธ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€

Controller

if(item.getPrice() != null && item.getItemName()!=null)
{
    int resultPrice = item.getPrice() * item.getQuantity();
    if(resultPrice<10000)
    {
        bindingResult.addError(new ObjectError("item","๊ฐ€๊ฒฉ * ์ˆ˜๋Ÿ‰์˜ ํ•ฉ์€ 10,000์› ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค." +
        "ํ˜„์žฌ ๊ฐ’ = " + resultPrice));
    }
}

ํŠน์ • ํ•„๋“œ๋ฅผ ๋„˜์–ด์„œ๋Š” ์˜ค๋ฅ˜๊ฐ€ ์žˆ์œผ๋ฉด ObjectError ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ bindingResult์— ๋‹ด์•„๋‘๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

addForm 

<div th:if="${#fields.hasGlobalErrors()}">
    <p class="field-error" th:each="err : ${#fields.globalErrors()}"
       th:text="${err}">๊ธ€๋กœ๋ฒŒ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€</p>
</div>

ํƒ€์ž„๋ฆฌํ”„๋Š” ์Šคํ”„๋ง์˜ BindingResult๋ฅผ ํ™œ์šฉํ•ด์„œ ํŽธ๋ฆฌํ•˜๊ฒŒ ๊ฒ€์ฆ ์˜ค๋ฅ˜๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  • #fields : #fields๋กœ BindingResult๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ฒ€์ฆ ์˜ค๋ฅ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • th:errors : ํ•ด๋‹น ํ•„๋“œ์— ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์— ํƒœ๊ทธ๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ( th:if์˜ ํŽธ์˜ ๋ฒ„์ „ )
  • th:errorclass : th:field์—์„œ ์ง€์ •ํ•œ ํ•„๋“œ์— ์˜ค๋ฅ˜๊ฐ€ ์žˆ์œผ๋ฉด class ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

 

ํ•„๋“œ ์˜ค๋ฅ˜ - FieldError

FieldError ์ƒ์„ฑ์ž ํŒŒ๋ผ๋ฏธํ„ฐ

  • objectName : @ModelAttribute ์ด๋ฆ„
  • field : ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ํ•„๋“œ ์ด๋ฆ„
  • defaultMessage : ๊ธฐ๋ณธ ์„ค์ •ํ•  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€
  • + rejectedValue : ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๊ฑฐ์ ˆ๋œ ๊ฐ’
  • + bindingFailure : ํƒ€์ž… ์˜ค๋ฅ˜ ๊ฐ™์€ ๋ฐ”์ธ๋”ฉ ์‹คํŒจ์ธ์ง€, ๊ฒ€์ฆ ์‹คํŒจ์ธ์ง€ ๊ตฌ๋ถ„ ๊ฐ’
  • + codes : ๋ฉ”์‹œ์ง€ ์ฝ”๋“œ
  • + arguments : ๋ฉ”์‹œ์ง€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ธ์ž

๋’ค์— ๋„ค๊ฐœ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ๋’ค์—์„œ ๋‹ค๋ฃจ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

// ๊ฒ€์ฆ ๋กœ์ง - ์ƒํ’ˆ๋ช…
if(!StringUtils.hasText(item.getItemName()))
{
    bindingResult.addError(new FieldError("item","itemName","์ƒํ’ˆ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."));
}

// ๊ฒ€์ฆ ๋กœ์ง - ๊ฐ€๊ฒฉ
if(item.getPrice()==null || item.getPrice()<1000 || item.getPrice() > 1000000)
{
    bindingResult.addError(new FieldError("item","price","๊ฐ€๊ฒฉ์€ 1,000 ~ 1,000,000๊นŒ์ง€ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค."));
}

// ๊ฒ€์ฆ ๋กœ์ง - ์ˆ˜๋Ÿ‰
if(item.getQuantity() == null || item.getQuantity() >= 9999)
{
    bindingResult.addError(new FieldError("item","quantity","์ˆ˜๋Ÿ‰์€ ์ตœ๋Œ€ 9,999๊นŒ์ง€ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค."));
}

 

์ƒํ’ˆ๋ช… ๊ฒ€์ฆ ๋กœ์ง์„ ์˜ˆ๋ฅผ๋“ค๋ฉด,

objectName = "item", field = "itemName", defaultMessage = "์ƒํ’ˆ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค" ๋กœ ์ง€์ •ํ–ˆ๋Š”๋ฐ,

if์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋ฉด objectName์„ @ModelAttribute Item "item"์œผ๋กœ, "itemName"์„ ํ•„๋“œ์ด๋ฆ„์œผ๋กœ, "์ƒํ’ˆ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค"๋ฅผ ๊ธฐ๋ณธ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋กœ ์„ค์ •ํ•ด์„œ bindingResult์— ๋”ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

 

@ModelAttribute์— ๋ฐ”์ธ๋”ฉ ์‹œ ํƒ€์ž… ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด

BindingResult๊ฐ€ ์žˆ์œผ๋ฉด โžฃ @ModelAttribute์— ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ์‹œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์˜ค๋ฅ˜ ์ •๋ณด๋ฅผ BindingResult์— ๋‹ด์•„์„œ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. 

BindingResult๊ฐ€ ์—†์œผ๋ฉด โžฃ 400 ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด์„œ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š๊ณ , ์˜ค๋ฅ˜ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

 

์ฆ‰ BindingResult๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํƒ€์ž…์˜ค๋ฅ˜๋Š” ์Šคํ”„๋ง์ด ์ž๋™์œผ๋กœ BindingResult์— FieldError๋ฅผ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.

 

BindingResult๋ฅผ ์‚ฌ์šฉํ•ด ๊ฒ€์ฆ ์˜ค๋ฅ˜๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์„ธ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

1.  ์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๋„ฃ์–ด์ค€๋‹ค.(ํ•„๋“œ ์˜ค๋ฅ˜, ๊ธ€๋กœ๋ฒŒ ์˜ค๋ฅ˜)

2. @ModelAttribute์˜ ๊ฐ์ฒด์— ํƒ€์ž… ์˜ค๋ฅ˜ ๋“ฑ์œผ๋กœ ๋ฐ”์ธ๋”ฉ์ด ์‹คํŒจํ•˜๋Š” ๊ฒฝ์šฐ ์Šคํ”„๋ง์ด FieldError ์ƒ์„ฑํ•ด์„œ BindingResult์— ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.

3. Validator ์‚ฌ์šฉ

 

<์ •๋ฆฌ>

BindingResult, FieldError, ObjectError๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๊ณ ๊ฐ์ด ์ž…๋ ฅํ•œ ๋‚ด์šฉ์ด ๋ชจ๋‘ ์‚ฌ๋ผ์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 


FieldError, ObjectError ์ถ”๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ •

FieldError๋Š” ์˜ค๋ฅ˜ ๋ฐœ์ƒ์‹œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๊ฐ’์„ ์ €์žฅํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

@PostMapping("/add")
public String addItemV2(@ModelAttribute Item item, BindingResult bindingResult,
                        RedirectAttributes redirectAttributes)
{
    if(!StringUtils.hasText(item.getItemName()))
    {
        bindingResult.addError(
                new FieldError("item",
                        "itemName",
                        item.getItemName(),
                        false,
                        null,
                        null,
                        "์ƒํ’ˆ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."));
    }

    // ๊ฒ€์ฆ ๋กœ์ง - ๊ฐ€๊ฒฉ
    if(item.getPrice()==null || item.getPrice()<1000 || item.getPrice() > 1000000)
    {
        bindingResult.addError(
                new FieldError("item",
                        "price",
                        item.getPrice(),
                        false,
                        null,
                        null,
                        "๊ฐ€๊ฒฉ์€ 1,000 ~ 1,000,000๊นŒ์ง€ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค."));
    }

    // ๊ฒ€์ฆ ๋กœ์ง - ์ˆ˜๋Ÿ‰
    if(item.getQuantity() == null || item.getQuantity() >= 9999)
    {
        bindingResult.addError(
                new FieldError("item",
                        "quantity",
                        item.getQuantity(),
                        false,
                        null,
                        null,
                        "์ˆ˜๋Ÿ‰์€ ์ตœ๋Œ€ 9,999๊นŒ์ง€ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค."));
    }

    if(item.getPrice() != null && item.getItemName()!=null)
    {
        int resultPrice = item.getPrice() * item.getQuantity();
        if(resultPrice<10000)
        {
            bindingResult.addError(
                    new ObjectError("item",
                            null,
                            null,
                            "๊ฐ€๊ฒฉ * ์ˆ˜๋Ÿ‰์˜ ํ•ฉ์€ 10,000์› ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ๊ฐ’ = " + resultPrice));
        }
    }

    if(bindingResult.hasErrors())
    {
        log.info("Error message = {}",bindingResult);
        return "validation/v2/addForm";
    }

    // ์„ฑ๊ณต ๋กœ์ง
    Item savedItem = itemRepository.save(item);
    redirectAttributes.addAttribute("itemId", savedItem.getId());
    redirectAttributes.addAttribute("status", true);
    return "redirect:/validation/v2/items/{itemId}";
}

 

FiledError๋Š” ๋‘๊ฐ€์ง€ ์ƒ์„ฑ์ž๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

FieldError ์ƒ์„ฑ์ž ํŒŒ๋ผ๋ฏธํ„ฐ

  • objectName : @ModelAttribute ์ด๋ฆ„
  • field : ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ํ•„๋“œ ์ด๋ฆ„
  • defaultMessage : ๊ธฐ๋ณธ ์„ค์ •ํ•  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€
  • + rejectedValue : ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๊ฑฐ์ ˆ๋œ ๊ฐ’
  • + bindingFailure : ํƒ€์ž… ์˜ค๋ฅ˜ ๊ฐ™์€ ๋ฐ”์ธ๋”ฉ ์‹คํŒจ์ธ์ง€, ๊ฒ€์ฆ ์‹คํŒจ์ธ์ง€ ๊ตฌ๋ถ„ ๊ฐ’
  • + codes : ๋ฉ”์‹œ์ง€ ์ฝ”๋“œ ( defalutMessgae ๋Œ€์ฒดํ™” ํ• ๋•Œ ์‚ฌ์šฉ, ๋’ค์— ์„ค๋ช… )
  • + arguments : ๋ฉ”์‹œ์ง€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ธ์ž ( defalutMessgae ๋Œ€์ฒดํ™” ํ• ๋•Œ ์‚ฌ์šฉ, ๋’ค์— ์„ค๋ช… )
if(!StringUtils.hasText(item.getItemName()))
{
    bindingResult.addError(
            new FieldError("item",
                    "itemName",
                    item.getItemName(),
                    false,
                    null,
                    null,
                    "์ƒํ’ˆ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."));
}

// ๊ฒ€์ฆ ๋กœ์ง - ๊ฐ€๊ฒฉ
if(item.getPrice()==null || item.getPrice()<1000 || item.getPrice() > 1000000)
{
    bindingResult.addError(
            new FieldError("item",
                    "price",
                    item.getPrice(),
                    false,
                    null,
                    null,
                    "๊ฐ€๊ฒฉ์€ 1,000 ~ 1,000,000๊นŒ์ง€ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค."));
}

// ๊ฒ€์ฆ ๋กœ์ง - ์ˆ˜๋Ÿ‰
if(item.getQuantity() == null || item.getQuantity() >= 9999)
{
    bindingResult.addError(
            new FieldError("item",
                    "quantity",
                    item.getQuantity(),
                    false,
                    null,
                    null,
                    "์ˆ˜๋Ÿ‰์€ ์ตœ๋Œ€ 9,999๊นŒ์ง€ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค."));
}

rejectedValue๋Š” ๋ฐ”๋กœ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๊ฐ’์„ ์ €์žฅํ•˜๋Š” ํ•„๋“œ์ž…๋‹ˆ๋‹ค.

rejectedValue ์„ค์ •ํ•œ ํ•„๋“œ์˜ค๋ฅ˜ - ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ๊ฐ’ ์œ ์ง€.

ํƒ€์ž„๋ฆฌํ”„์˜ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๊ฐ’ ์œ ์ง€

  • th:field="*{price}"
  • ํƒ€์ž„๋ฆฌํ”„์˜ th:field๋Š” ๋งค์šฐ ๋˜‘๋˜‘ํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋Š”๋ฐ, ์ •์ƒ ์ƒํ™ฉ์—๋Š” ๋ชจ๋ธ ๊ฐ์ฒด์˜ ๊ฐ’์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด FieldError์—์„œ ๋ณด๊ด€ํ•œ ๊ฐ’์„ ์‚ฌ์šฉํ•ด์„œ ๊ฐ’์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

์Šคํ”„๋ง์˜ ๋ฐ”์ธ๋”ฉ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ

  • ํƒ€์ž… ์˜ค๋ฅ˜๋กœ ๋ฐ”์ธ๋”ฉ์— ์‹คํŒจํ•˜๋ฉด ์Šคํ”„๋ง์€ FieldError๋ฅผ ์ƒ์„ฑํ•˜๋ฉด์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๊ฐ’์„ ์ž๋™์œผ๋กœ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค!
  • ๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น ์˜ค๋ฅ˜๋ฅผ BindingResult ์— ๋‹ด์•„์„œ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํƒ€์ž… ์˜ค๋ฅ˜ ๊ฐ™์€ ๋ฐ”์ธ๋”ฉ ์‹คํŒจ์‹œ์—๋„ ์‚ฌ์šฉ์ž์˜ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ •์ƒ์ ์œผ๋กœ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

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

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

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