티스토리 뷰

검증을 하는 이유

회원가입 부분에서 검증을 필수이다. 양식에 맞는 정보를 입력할 수 있기에 구현을 해야된다.

 

검증 방법은 2가지가 있다.

  • BeanValidation의 groups 기능을 사용한다.
  • Item을 직접 사용하지 않고, ItemSaveForm, ItemUpdateForm 같은 폼 전송을 위한 변도의 모델 객체를 만든다.

Gradle 추가

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

Bean Validation - group

@Data
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)
    private Integer price;

    @NotNull(groups = {SaveCheck.class, UpdateCheck.class})
    @Max(value = 9999, groups = {SaveCheck.class}) //수정 요구사항 추가
    private Integer quantity;

    public Item() {
    }

    public Item(String itemName, Integer price, Integer quantity) {
        this.itemName = itemName;
        this.price = price;
        this.quantity = quantity;
    }
}

 

groups = "" 을 사용하여 사용할 객체를 선택할 수 있다.

 

id는 UpdateCheck 일 때만 사용

@NotNull(groups = UpdateCheck.class) // 수정요구 사항
    private Long id;

 

itemName은 SaveCheck.class, UpdateCheck.class 일 때 확인

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

 

SaveCheck, UpdateCheck

 

인터페이스로 만들고 싶은 이름으로 만들어주기만 하면 된다.

 

컨트롤러 사용법

 @PostMapping("/{itemId}/edit")
    public String editV2(@PathVariable Long itemId, @Validated(UpdateCheck.class) @ModelAttribute Item item, BindingResult bindingResult) {

        // 특정 필드가 아닌 복합 룰 검증
        if (item.getPrice() != null && item.getQuantity() != null){
            int resultPrice = item.getPrice() * item.getQuantity();
            if(resultPrice<10000){
                bindingResult.reject("totalPriceMin", new Object[]{10000, resultPrice} , null);
            }
        }

        if(bindingResult.hasErrors()){
            log.info("errors={}", bindingResult);
            return "validation/v3/editForm";
        }
        itemRepository.update(itemId, item);
        return "redirect:/validation/v3/items/{itemId}";
    }

 

@Validated(UpdateCheck.class) 를 사용함으로서 검증에 사용할 객체를 선택했다.

 

Groups에 대해서

  • groups 기능을 사용해서 각각 다르게 검증을 할 수 있다. groups 기능을 사용하니 item은 물론이고 전반적으로 복잡도가 늘어났다.
  • groups는 실제 잘 사용하지 않는다. 그 이유는 실무에서는 등록용 폼 객체와 수정용 폼 객체를 따로 분리해서 사용하기 때문이다.
  • 회원 가입의 경우 회원 정보와 약관 정보, 주민정보 등 다양한 정보를 받는다. 회원 정보 변경과는 필요한 정보 차이가 나도 조건도 다르다.

Form 전송 객체 분리

수정을 위한 Form 객체와 입력을 위한 Form 객체를 따로 만든다.

 

ItemSaveForm

package hello.itemservice.web.validation.form;

import hello.itemservice.domain.item.SaveCheck;
import hello.itemservice.domain.item.UpdateCheck;
import lombok.Data;
import org.hibernate.validator.constraints.Range;

import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Data
public class ItemSaveForm {

    @NotBlank
    private String itemName;

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

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

 

ItemUpdateForm

package hello.itemservice.web.validation.form;

import lombok.Data;
import org.hibernate.validator.constraints.Range;

import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Data
public class ItemUpdateForm {

    @NotNull
    private Long id;

    @NotBlank
    private String itemName;

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

    private Integer quantity;
}

 

컨트롤러

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

        // 특정 필드가 아닌 복합 룰 검증
        if (form.getPrice() != null && form.getQuantity() != null){
            int resultPrice = form.getPrice() * form.getQuantity();
            if(resultPrice<10000){
                bindingResult.reject("totalPriceMin", new Object[]{10000, resultPrice} , null);
            }
        }

        // 검증에 실패하면 다시 입력 폼으로
        if (bindingResult.hasErrors()){
            log.info("errors = {}", bindingResult);
            return "validation/v4/addForm";
        }

        Item item = new Item();
        item.setItemName(form.getItemName());
        item.setPrice(form.getPrice());
        item.setQuantity(form.getQuantity());

        //검증 성공 로직
        Item savedItem = itemRepository.save(item);
        redirectAttributes.addAttribute("itemId", savedItem.getId());
        redirectAttributes.addAttribute("status", true);
        return "redirect:/validation/v4/items/{itemId}";
    }

 

@Validated @ModelAttribute("item") ItemSaveForm form

ItemSaveForm 객체를 받는다.

@ModelAttribute("item")를 한 이유는 템플릿에서 받는 객체의 이름이 item이기에 설정을 해준것이다.

 

Groups에 비해서 추가된 것은 Item객체에 입력을 받는 과정이 추가된 것이다.

컨트롤러에서의 길이가 조금 늘어나긴 했지만 객체의 역활이 분리되었다.

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함