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

41. Form 전송객체 분리

sdafdq 2023. 9. 4. 03:09

사실 대부분의 경우가 (예를 들어 회원가입 시) 우리가 만든 User 객체등과 맞지 않다.

예를 들어 회원가입 시에는 기본 User에 대한 정보 뿐 아니라 수많은 약관등의 정보를 가지고 온다.

 

그래서 컨트롤러에서 User로 받기 보다는 따로 Form전용 객체를 만들고, 거기서 User를 만들어 필요에 맞게 쓴다.

 

 

groups 기능은 실무에서 잘 사용하지 않는다.

 

 

보통 등록과 수정은 다른 객체로 만든다.

 

그래서 검증도 중복이 되질 않는다.

 

@Data
public class ItemSaveForm {

    @NotBlank
    private String itemName;

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

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

    public Item getItem(){
        return new Item(this.itemName, this.price, this.quantity);
    }

}

 

 

@Data
public class ItemUpdateForm {

    @NotNull
    private Long id;
    @NotBlank
    private String itemName;

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

    private Integer quantity;

    public Item getItem(){
        return new Item(this.itemName, this.price, this.quantity);
    }
    
}

 

음... 뭔가 비슷한게 많다. @애노테이션 만약 이거 인터페이스로 만들어도 재정의 할 수 있을지는..

 

여튼 이렇게 따로 구분해서 만드니 검증을 다르게 할 수 있다.

 

 

@PostMapping("/add")
public String addItem(@Validated @ModelAttribute("item") ItemSaveForm itemForm, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
    //검증 오류 보관
    validMultiplePrice(itemForm, bindingResult);

    if(bindingResult.hasErrors()){
        log.info("errors = {}", bindingResult);
        return "/validation/v4/addForm";
    }
    Item item = itemForm.getItem();
    Item savedItem = itemRepository.save(item);
    redirectAttributes.addAttribute("itemId", savedItem.getId());
    redirectAttributes.addAttribute("status", true);
    return "redirect:/validation/v4/items/{itemId}";
}

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

private void validMultiplePrice(ItemUpdateForm 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 @ModelAttribute("item") ItemUpdateForm itemForm, BindingResult bindingResult) {
    validMultiplePrice(itemForm, bindingResult);

    if(bindingResult.hasErrors()){
        return "/validation/v4/editForm";
    }
    Item item = itemForm.getItem();
    itemRepository.update(itemId, item);
    return "redirect:/validation/v4/items/{itemId}";
}

대충 복합검증 만들어 준 것은 오버로딩 해주긴 했는데.. 어차피 Item 생성을 하니 오버로딩 필요 없었을지도..

 

여튼 이렇게 따로 구분 해 놓으면 관리하기가 정말 편하다.

 

@ModelAttribute("item") 이거는 넘어온 정보를 기존 템플릿에 맞게 사용하기 위해 원래 Item이 쓰던 이름으로 넘겼다.