스프링/4. 스프링 MVC-2

40. 컨트롤러 간 검증이 다른 경우.

sdafdq 2023. 9. 3. 18:45

우리는 앞서 

public class Item {
    private Long id;
    @NotBlank
    private String itemName;

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

    @NotNull
    @Max(9999)
    private Integer quantity;

    public Item() {
    }

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

이렇게 애노테이션으로 검증을 손쉽게 적용 했다.

 

하지만 문제의 요지가 있을 수 있는 점은,

 

id는 중복을 피하기 위해 서버에서 지정해 주는 것이고, 클라이언트도 입력할 필요가 없다.

 

만약 수정 시에 id가 NotNull이어야 한다면? (http 메시지를 바꿔서 보내는 것은 너무 쉽다.)

 

물론 id에 @NotNull 붙이면 되는거 아니야? 라고 생각할 수도 있지만,

 

그렇게 된다면 우리는 처음 상품을 등록할 때 id를 넣지 않으므로 상품 등록할 때는 필연적으로 상품등록이 거부당한다.

 

 

 

이럴 땐 빈 검증의 그룹 기능을 쓰면 된다.

 

먼저, 오로지 분리용도로 쓰기 위한 인터페이스를 만든다.

SaveCheck과 UpdateCheck이라는 비어있는 인터페이스를 만든다.

그 후

public class Item {

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

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

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

    @NotNull(groups = {UpdateCheck.class,SaveCheck.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;
    }
}

이건 어떤 그룹에 포함되요, 이런 식으로 알려주면 된다.

 

 

@PostMapping("/add")
public String addItem(@Validated(value = SaveCheck.class) @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
    //검증 오류 보관

    validMultiplePrice(item, bindingResult);

    if(bindingResult.hasErrors()){
        log.info("errors = {}", bindingResult);
        return "/validation/v3/addForm";
    }

    Item savedItem = itemRepository.save(item);
    redirectAttributes.addAttribute("itemId", savedItem.getId());
    redirectAttributes.addAttribute("status", true);
    return "redirect:/validation/v3/items/{itemId}";
}

private void validMultiplePrice(Item item, BindingResult bindingResult){
    if(item.getPrice() != null && item.getQuantity() != null){
        int resultPrice = item.getPrice() * item.getQuantity();
        if( resultPrice < 10000){
            bindingResult.reject("MinQuantityPrice", new Object[]{10000, resultPrice}, null);
        }
    }
}


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

    if(bindingResult.hasErrors()){
        return "/validation/v3/editForm";
    }

    itemRepository.update(itemId, item);
    return "redirect:/validation/v3/items/{itemId}";
}

Validate 안에 이건 어떤 그룹의 검증을 쓸건지 명시한다.

value = 그룹클래스 이렇게 쓰는데,

 

value = <- 이거는 생략해도 된다. 넣어야 할 속성이 하나만 있으면.

 

 

이렇게 하면,

Item에서 지정한 그룹만 검증을 사용한다.

 

 

참고로 @Valid는 이런 그룹 기능이 없다.

 

 

'스프링 > 4. 스프링 MVC-2' 카테고리의 다른 글

42. Http 메시지(Rest API) 검증  (0) 2023.09.04
41. Form 전송객체 분리  (0) 2023.09.04
39. 빈 검증 오브젝트 에러  (0) 2023.09.03
38. 빈 검증기 오류메시지 바꾸기  (0) 2023.09.03
37. 빈 검증  (0) 2023.09.02