베어_
TechBear
베어_
전체 방문자
오늘
어제
  • 분류 전체보기 (336)
    • Spring (33)
      • 개념 (13)
      • Security (5)
      • 실습 (1)
      • 토비 스프링 (11)
    • JPA (6)
    • 프로젝트 기록 (24)
    • DB (13)
    • JAVA (18)
    • 알고리즘 (50)
      • 유형정리 (8)
      • Baekjoon (21)
      • LeetCode (18)
    • 디자인패턴 (0)
    • 개발서적 (79)
      • Effective Java (78)
      • 객체지향의 사실과 오해 (1)
    • 독후감 (4)
    • 보안 (2)
    • 운영체제(OS) (53)
      • 공룡책 (53)
    • 컴퓨터 네트워크 (28)
      • 컴퓨터 네트워크 하향식 접근 (23)
    • 자료구조 (1)
    • DevOps (2)
    • 앱 개발 (20)
      • 안드로이드 스튜디오 (20)

블로그 메뉴

    공지사항

    인기 글

    태그

    • 자바8
    • java
    • Spring
    • jpa
    • BFS
    • dfs
    • 백준
    • 스프링시큐리티
    • leetcode
    • 운영체제
    • 스레드
    • 스프링
    • 데이터베이스
    • 함수형인터페이스
    • 이펙티브자바
    • C++
    • 코드업
    • 알고리즘
    • 토비스프링
    • 자바

    최근 댓글

    최근 글

    티스토리

    hELLO · Designed By 정상우.
    베어_

    TechBear

    [Spring] Validation
    Spring/개념

    [Spring] Validation

    2022. 4. 27. 10:22

    검증 처리 코드

       1. 검증 오류를 보관할 HashMap을 생성한다.

       2. 상품 이름이 빠지거나, 가격의 범위를 넘어서거나, 수량 범위를 넘어설 때 검증할 로직을 추가한다.

       3. 특정 필드가 아닌 복합 적인 검증 로직도 추가한다.

       4. 만약 2번 3번에서 검증에 실패하면 errors에 에러 이유가 들어가 있을 것이고, 에러가 있으면 validation/v1/addForm으로 다시 이동한다.

    @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()) { // hasError로 바꾸는게 좋음. 부정의 부정이라
            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}";
    }

     

     

    상품명이 빈 값이기 때문에 페이지가 재로딩된다.

    근데 여기서 궁금한 것이 생긴다. 페이지를 다시 로딩 했는데 어떻게 폼에 값이 그대로 남아 있는가 ?

    1. @ModelAttribute 속성 때문에 model.add("item", item)을 자동으로 해주며, 이를 view로 전송한다.

    2. 이를 HTML파일에서 읽어들일 수 있기 때문에 폼에 값이 그대로 남게 된다.

     

    리팩토링

    @BindingResult

       1. BindingResult는 Model에 자동으로 포함된다. 

       2. @ModelAttribute에 바인딩 시 타입 오류가 발생하면 BindingResult에 오류 정보를 담아서 컨트롤러를 호출한다. 

        Cf ) BindingResult가 없으면 400 오류가 발생하면서 컨트롤러가 호출되지 않고, 오류 페이지로 이동한다.

     

     

    1. BindingResult를 선언한다. 이 때 위치는 @ModelAttribute가 붙은 파라미터 바로 옆에 선언해야 한다. -> 에러가 생기면 @ModelAttribute가 붙은 파라미터에 바인딩 된 결과가 담긴다.

    @PostMapping("/add")                         // item에 바인딩 된 결과가 담김
    public String addItemV1(@ModelAttribute Item item, BindingResult bindingResult, 
            RedirectAttributes redirectAttributes, 
            Model model) {

     

    2. 필드에 오류가 있으면 FieldError 객체를 생성해서 bindingResult에 담아두면 된다.

    // 검증 로직
    if (!StringUtils.hasText(item.getItemName())) {
        bindingResult.addError(new FieldError("item", "itemName", "상품 이름은 필수 입니다."));
    }
    if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) {
        bindingResult.addError(new FieldError("item", "price", "가격은 1,000 ~ 1,000,000 까지 허용합니다."));
    }
    if (item.getQuantity() == null || item.getQuantity() >= 9999) {
        bindingResult.addError(new FieldError("item", "price", "수량은 최대 9,999 까지 허용합니다."));
    }

     

    3. 특정 필드를 넘어서는 복합 오류의 경우 ObjectError를 생성해서 bindingResult에 담아야 한다.

    // 특정 필드가 아닌 복합 룰 검증
    if (item.getPrice() != null && item.getQuantity() != null) {
        int resultPrice = item.getPrice() * item.getQuantity();
        if (resultPrice < 10000) {
            // 필드가 없음. 글로벌 오류임 따라서 ObjectError이용
            bindingResult.addError(new ObjectError("item", "가격 * 수량의 합은 10,000원 이상이어야 합니다."));
        }
    }

     

    4. 검증에 실패하면 다시 입력 폼으로 이동하게 한다.

    // 검증에 실패하면 다시 입력 폼으로
    if (bindingResult.hasErrors()) { // 바인딩리서트는 모델에 안담아도 스프링이 알아서 해 줌.
        return "validation/v2/addForm";
    }

     

      'Spring/개념' 카테고리의 다른 글
      • [Spring] RequestMapping과 Controller
      • [Spring] 리다이렉트 동작 원리
      • [Spring] 의존성 주입과 동일 타입 클래스 문제 해결
      • [Spring] 스프링 빈 콜백
      베어_
      베어_
      Today I learned | 문제를 해결하는 개발자

      티스토리툴바