검증을 언제 할까? 우리가 상품을 등록한다고 해보자.
상품 등록 폼에 들어가서 우리는 상품정보를 작성할것 이다.
상품 이름, 가격, 수량을 입력해야한다면 해당 데이터 마다 검증이 필요하다.
검증이 성공했을 경우는 매우 편하다.

1. 상품 등록 폼에 들어간다.
@GetMapping("/add")
public String addForm(Model model) {
model.addAttribute("item", new Item());
return "validation/v2/addForm";
}
2. 상품 정보를 작성하고 상품을 저장 버튼을 누른다.
3. 서버에서는 상품 정보를 받고 완료 페이지를 리다이렉트를 해준다.
@PostMapping("/add")
public String addItem(@ModelAttribute Item item, RedirectAttributes redirectAttributes, Model model) {
.
.
.
return "redirect:/validation/v2/items/{itemId}";
}
만약에 검증에 실패 할 경우는 어떤 프로세스로 동작해야할까?

1. 상품 등록 폼에 들어간다.
2. 상품 정보를 작성하고 상품을 저장 버튼을 누른다. (여기까지는 동일)
3. 컨트롤러에서 검증에 실패한다면 우리는 다시 실패한 값과 실패하지 않는 값 그리고 어떤 값이 잘못 입력되었는지도 클라이언트에게 알려줘야 한다.
3번 부분을 직접 개발을 해보자...
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.getPrice() != null && item.getQuantity() != null) {
int resultPrice = item.getPrice() * item.getQuantity();
if (resultPrice < 10000) {
errors.put("globalError", "가격 * 수량의 합은 10,000원 이상이어야 합니다. 현재 값 = " + resultPrice);
}
}
만약에 내가 검증하고 싶은 부분이 필드에 없다면 필드 명을 정해서 키값에다가 넣고 value에 검증 실패한 이유를 작성한다.
if (!errors.isEmpty()) {
model.addAttribute("errors", errors);
return "validation/v1/addForm";
}
만약에 에러가 하나라도 있다면 성공 페이지로 리다이렉트가 아닌
오류 메시지를 출력하기 위해 model 에 errors 를 담고, 입력 폼이 있는 뷰 템플릿으로 보낸다.
<전체코드>
@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", "수량은 최대 9,999 까지 허용합니다.");
}
//특정 필드가 아닌 복합 룰 검증
if (item.getPrice() != null && item.getQuantity() != null) {
int resultPrice = item.getPrice() * item.getQuantity();
if (resultPrice < 10000) {
errors.put("globalError", "가격 * 수량의 합은 10,000원 이상이어야 합니다. 현재 값 = " + resultPrice);
}
}
//검증에 실패하면 다시 입력 폼으로
if (!errors.isEmpty()) {
log.info("errors = {} ", 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}";
}
※ RedirectAttributes : 리다이렉트 시에 데이터를 넘겨주고 싶어 사용 됨
문제점
이렇게 개발했을때 아직 문제 점은 존재한다.
1. 뷰 템플릿에서 중복 처리 코드가 많다.
2. 타입 오류 처리가 안됨
가격의 타입은 Integer이다. 만약에 상품 정보 폼에서 문자가 들어온다면 에러가 발생 할 것이다.
하지만 컨트롤러 들어오기 전에 에러가 발생한다. 그래서 우리가 처리 할 수없이 화면은 오류페이지가 나온다.
3. 만약 컨트롤러가 호출된다고 해서 우리는 문자열로 들어온 가격을 보관 할 수 없다.
'Spring > Validation' 카테고리의 다른 글
| Spring ) 서버에서 검증을 하는 이유 (0) | 2022.12.24 |
|---|