먼저 아래 사진과 같은 PRG(POST, Redirect, GET) 형식의 상품 등록 흐름이 있다고 가정하자.

image.png

그럼 우리는 어디서 validation을 거쳐 잘못됐다는 걸 프론트에게 어떻게 건네줘야 할까?

원래였으면 상품 등록 폼에서 POST /add를 보내면 리다이렉트 되며 상품이 무조건 등록되는데 아래 그림처럼 POST /add , 즉 상품등록 요청을 POST로 보냈을 시에 오류(이름 null, 형식오류 등)를 검증해야 프론트에게 오류가 있음을 알려줄 수 있을 것이다!!

정확히는 Model에 “이름 형식이 잘못되었습니다” “가격 형식 오류입니다” 등 오류메시지와 함께 기존의 맞는 내용들은 채워넣고 상품 등록 폼을 렌더링 해주어야 깔끔한 흐름일 것이다!!

image.png

아래 코드는 아이템을 POST로 add하는 과정에서 Map 자료구조를 이용해 오류 검증을 쫘르륵 한 후 Map에 오류가 있으면 validation에 걸리고, 없으면 성공로직을 실행하는 날것의 코드이다!

주석으로 Model과 ModelAttribute의 특징을 이용한 것을 잘 써놨으니 꼭 자세히 보고 이해하자.

   @PostMapping("/add") 
    public String addItem(@ModelAttribute Item item, RedirectAttributes redirectAttributes, Model model) {
// ModelAttirbute기 때문에 검증에 실패하여 뷰 반환을 통해 입력폼으로 돌아가도 그 전 아이템의 내용이 그대로 남아있다!!
// model.addAtrribute를 자동으로 해주잖냐!!
        // 검증 오류 결과를 보관
        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", "수량은 최대 9,999개까지 가능합니다");
        }

        // 특정 필드가 아닌 복합 룰 검증
        if(item.getQuantity() != null || item.getPrice() != null) {
            int resultPrice = item.getPrice() * item.getQuantity();
            if(resultPrice < 10000) {
                errors.put("globalError", "가격 * 수량의 합은 10000원 이상이어야 합니다. 현재 값 : " + resultPrice);
            }
        }

        // 검증에 실패하면 다시 입력 폼으로
        if(!errors.isEmpty()) {
		        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}";
    }
    
    // POST 매개변수 ModelAttribute의 자동으로 model.addAttribute 해주는 특징때문에 검증 실패시 뷰만 반환을 해준거임! Model에 POST시 썻던 아이템 내용이 올라가있으니!
    // 이 GET /add 은 진짜 빈 아이템으로 다시 리다이렉트가 필요할 때 쓰는 것! 홈페이지 불러 올 때!
    // 그래서 빈 값으로 추가하는 거구나~
        @GetMapping("/add")
    public String addForm(Model model) {
        model.addAttribute("item", new Item());
        return "validation/v1/addForm";
    }

validation에 걸리면 다시 요청 폼을 요청하는 건데, 그 전 값이 남아있게 하기위해 검증 실패시 그냥 뷰 반환만 한 이유!! 꼭 알고가기@@@@@

image.png