오류코드와 메시지처리(1)

JIWOO YUN·2024년 2월 6일
0

SpringMVC2

목록 보기
11/26
post-custom-banner

FieldError에는 2가지 생성자가 존재한다.

public FieldError(String objectName,String field, String defaultMessage);
public FieldError(String objectName,String field, @Nullable Object rejectValue, boolean bindingFailure,@Nullable String[] codes,@Nullable Object[] arguments, @Nullable String defaultMessage)
  • field : 오류 필드
  • rejectValue : 사용자가 입력한 값
    • 여기에 오류가 발생했을때 사용자가 입력한 값을 저장하는 필드
    • 이게 없다면 내가 전에 입력한 것들이 오류가 발생하면 다 날라가게된다.
  • bindingFailure : 타임오류 같은 바인딩 실패인지 검증실패인지 구분값
  • codes : 메시지 코드
  • arguments : 메시지에서 사용하는 인자
  • defaultMessage : 기본 오류 메시지
  • FieldError와 ObjectError의 생성자는 codes 와 argouments 를 제공하는데 이 두가지가 오류 발생기 오류코드로 메시지를 찾기위해서 사용된다.

Error 메시지 파일 생성

  • errors.properties라는 별도의 파일로 오류 메시지 관리
  • errors.properties파일을 인식할 수 있게 application.yml 파일에 다음 설정을 추가한다.
    • 이 부분을 생략시 messages 를 기본으로 인식
spring:
  messages:
   basename: messages, errors

Error.properties

required.item.itemName=상품 이름은 필수입니다.
range.item.price=가격은 {0} ~ {1} 까지 허용합니다.
max.item.quantity=수량은 최대 {0} 까지 허용합니다.
totalPriceMin=가격 * 수량의 합은 {0}원 이상이어야 합니다. 현재 값 = {1}

메시지 코드는 위의 properties를 사용해서 지정이 가능하고, 하나가 아니라 배열로 여러 값을 전달 할 수도 있다.

  • 순서대로 매칭해서 처음 매칭되는 메시지가 사용된다.

arguments : new Object[]{1000,1000000} 를 사용해서 코드의 {0} ,{1} 로 치환 할 값을 전달

변경한 코드 : addItemV3

    @PostMapping("/add")
    public String addItemV3(@ModelAttribute("item") Item item, BindingResult bindingResult,
                            RedirectAttributes redirectAttributes) {
        if (!StringUtils.hasText(item.getItemName())) {
            bindingResult.addError(new FieldError("item", "itemName",
                    item.getItemName(), false, new String[]{"required.item.itemName"}, null, null));
        }
        if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() >
                1000000) {
            bindingResult.addError(new FieldError("item", "price", item.getPrice(),
                    false, new String[]{"range.item.price"}, new Object[]{1000,1000000}, null));
        }
        if (item.getQuantity() == null || item.getQuantity() >= 10000) {
            bindingResult.addError(new FieldError("item", "quantity",
                    item.getQuantity(), false, new String[]{"max.item.quantity"}, new Object[]{9999}, null));
        }
        //특정 필드 예외가 아닌 전체 예외
        if (item.getPrice() != null && item.getQuantity() != null) {
            int resultPrice = item.getPrice() * item.getQuantity();
            if (resultPrice < 10000) {
                bindingResult.addError(new ObjectError("item", new String[]{"totalPriceMin"}, new Object[]{10000,item.getQuantity()*item.getPrice()}, null));
            }
        }
        if (bindingResult.hasErrors()) {
            log.info("errors={}", bindingResult);
            return "validation/v2/addForm";
        }
        //성공 로직
        Item savedItem = itemRepository.save(item);
        redirectAttributes.addAttribute("itemId", savedItem.getId());
        redirectAttributes.addAttribute("status", true);
        return "redirect:/validation/v2/items/{itemId}";
    }

FieldError와 ObejctError는 다루기 번거로운 점을 자동화해보자.

  • BindingResult의 경우 검증할 객체인 target 바로 다음에 오기 때문에 BindingResult는 이미 본인이 검증해야할 객체를 알고 있게 된다.
  • 확인을 위해서 log를 찍어보면 알수 있다.

로그를 찍어보니 확실하게 본인이 어떤걸 target으로 하고있는지 아는걸 확인할 수있다.

어떤 걸 target으로 하는지 알고있기 때문에 bindingResult 가 제공하는 rejectValue() 와 reject()를 사용하면 FieldError와 ObjectError를 직접 생성하지 않고 검증 오류를 다룰수 있게 된다.

rejectValue()

void rejectValue(@Nullable String field, String errorCode,@Nuallable Object[] errorArgs,
                @Nullable String defaultMessage);
  • field : 오류 필드명

  • errorCode : 오류 코드(메시지에 등록된 코드가 아님.)

  • errorArgs : 오류메시지에서{0}을 치환하기 위한 값

  • defaultMessage: 오류 메시지를 찾을 수 없을 때 사용하는 기본 메시지

bindingResult.rejectValue("price", "range", new Object[]{1000, 1000000}, null)
  • 이미 알고 있기 때문에 타겟에대한 정보는 없어도 제대로 돌아가게된다.
  • 여기서 원래는 properties에 적힌대로 경로를 적어줘야했지만 range로 적어도 제대로 작동이 된다. 이 이유는 MessageCodesResolver를 이해해야하는 데 이건 다음 장에서 추가로 진행하자.
profile
열심히하자
post-custom-banner

0개의 댓글