Validation

송수용·2022년 6월 29일
0

Validation

spring Validation을 이용한 유효성 검증

애플리케이션을 만들 때 검증 오류가 발생한다면, 오류화면으로 바로 이동한다.
그럴 경우 사용자는 처음부터 다시 폼을 이용해야하는데 번거로움을 느껴 사용자는 금방 떠나버릴 것이다.
웹 서비스는 폼 입력시 오류가 발생하면, 고객이 입력한 데이터를 유지한 상태로 어떤 오류가 발생했는지 친절하게 알려주어야 한다.

컨트롤러의 중요한 역할 중 하나는 HTTP 요청이 정상인지 검증하는 것이다.
그리고 정상 로직보다 이런 검증 로직을 잘 개발하는 것이 더 어려울 수 있다.

참고: 클라이언트 검증, 서버 검증

  • 클라이언트 검증은 조작할 수 있으므로 보안에 취약하다.
  • 서버만으로 검증하면, 즉각적인 고객 사용성이 부족해진다.
  • 둘을 적절히 섞어서 사용하되, 최종적으로 서버 검증은 필수
  • API방식을 사용하면 API 스펙을 잘 정의해서 검증 오류를 API 응답 결과에 잘 남겨주어야 한다.

프로젝트 설정 순서

  1. validation-start 의 폴더 이름을 validation 로 변경하자.
  2. 프로젝트 임포트
    File Open 해당 프로젝트의 build.gradle 을 선택하자. 그 다음에 선택창이 뜨는데, Open as
    Project 를 선택하자.
  3. ItemServiceApplication.main() 을 실행해서 프로젝트가 정상 수행되는지 확인

검증 직접 처리 - 소개

상품 저장 성공

사용자가 상품 등록 폼에서 정상 범위의 데이터를 입력하면, 서버에서는 검증 로직이 통과하고, 상품을 저장하고, 상품 상세 화면으로 redirect한다.

상품 저장 검증 실패

고객이 상품 등록 폼에서 상품명을 입력하지 않거나, 가격, 수량 등이 너무 작거나 커서 검증 범위를
넘어서면, 서버 검증 로직이 실패해야 한다. 이렇게 검증에 실패한 경우 고객에게 다시 상품 등록 폼을
보여주고, 어떤 값을 잘못 입력했는지 친절하게 알려주어야 한다.

검증 직접 처리 - 개발

ValidationItemControllerV1 - addItem() 수정

@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()) {
      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}";
  }

import org.springframework.util.StringUtils; 를 추가

검증시 오류가 발생하면 errors 에 담아둔다. 이때 어떤 필드에서 오류가 발생했는지 구분하기 위해
오류가 발생한 필드명을 key 로 사용한다. 이후 뷰에서 이 데이터를 사용해서 고객에게 친절한 오류
메시지를 출력할 수 있다.

특정 필드의 범위를 넘어서는 검증 로직

if (item.getPrice() != null && item.getQuantity() != null) {
      int resultPrice = item.getPrice() * item.getQuantity();
      if (resultPrice < 10000) {
        errors.put("globalError", "가격 * 수량의 합은 10,000원 이상이어야 합니다. 현재 값
                = " + resultPrice);
      }

특정 필드를 넘어서는 오류를 처리해야 할 수도 있다. 이때는 필드 이름을 넣을 수 없으므로 globalError
라는 key 를 사용한다.

검증에 실패하면 다시 입력 폼으로

    if (!errors.isEmpty()) {
      model.addAttribute("errors", errors);
      return "validation/v1/addForm";
    }

정리

  • 만약 검증 오류가 발생하면 입력 폼을 다시 보여준다.
  • 검증 오류들을 고객에게 친절하게 안내해서 다시 입력할 수 있게 한다.
  • 검증 오류가 발생해도 고객이 입력한 데이터가 유지된다.
profile
#공부중 #협업 #소통중시 #백엔드개발자 #능동적 #워커홀릭 #스파르타코딩 #항해99 #미니튜터 #Nudge #ENTJ #브레인스토밍 #아이디어뱅크

0개의 댓글