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

JIWOO YUN·2024년 2월 8일
0

SpringMVC2

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

검증 오류 코드는 2가지로 나뉜다.

  • 개발자가 직접 작성한 오류 코드 -> rejectValue()를 직접 호출
  • 스프링이 직접 검증 오류를 추가한 경우 -> 주로 타입 정보가 맞지않는다.

price 필드에 문제 "A" 를 입력할 경우

codes[typeMismatch.item.price,typeMismatch.price,typeMismatch.java.lang.Integer,ty
peMismatch]

이렇게 bindingResult가 담겨있을 것이다.

  • 현재 error.properties에 typeMisMatch에 대해서 처리를 안했기 때문에 스프링이 생성한 기본 메시지가 출력됨.
  • 원하는 메시지를 내보내고 싶은 경우 properties에 맞춰서 만들어 두자.
#추가
typeMismatch.java.lang.Integer=숫자를 입력해주세요.
typeMismatch=타입 오류입니다.


Validation 분리

  • 컨트롤러에서 검증 로직이 차지하는 부분이 매우 크기 때문에 별도의 클래스로 역할을 분리하자.

스프링은 검증을 체계적으로 제공하기 위해서 Validator라는 인터페이스를 제공한다.

public interface Validator {
	boolean supports(Class<?> clazz);
	void validate(Object target, Errors errors);
}
  • supports : 해당 검증기를 지원하는지 여부 확인
  • validate(Obejct target,Errors erros ) : 검증 대상객체와 bindingResult

validate에 target을 item으로 캐스팅을 하고 값이 들어있는지 여기서 검증을 진행해준다.

@Component
public class ItemValidator implements Validator {
    @Override
    public boolean supports(Class<?> clazz) {
        return Item.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {

        Item item = (Item) target;

        ValidationUtils.rejectIfEmptyOrWhitespace(errors,"itemName","required");

        if (item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() >
                1000000) {
            errors.rejectValue("price","range",new Object[]{1000,1000000},null);

        }
        if (item.getQuantity() == null || item.getQuantity() >= 10000) {
            errors.rejectValue("quantity","max",new Object[]{9999},null);
        }
        //특정 필드 예외가 아닌 전체 예외
        if (item.getPrice() != null && item.getQuantity() != null) {
            int resultPrice = item.getPrice() * item.getQuantity();
            if(resultPrice < 10000){
                errors.reject("totalPriceMin",new Object[]{10000,resultPrice},null);
            }
        }

    }
}
  • 역할이 분리되어서 컨트롤러 부분의 몸통이 줄어들게 되면서 이 검증 로직을 재사용도 가능할 수 있게 된다.
  • Compent를 등록해둠으로써 컴포넌트 스캔의 대상이 되어 bean에 등록을해두고 사용하면된다.

Validator 분리2

WebDataBinder 를 통해서 사용

  • 스프링의 파라미터 바인딩의 역할을 해주고 검증 기능도 내부에 포함한다.

컨트롤러에 밑의 코드를 추가

    @InitBinder
    public void init(WebDataBinder dataBinder){
        log.info("init Binder {}", dataBinder);
        dataBinder.addValidators(itemValidator);
    }
  • 이렇게 WebDatabinder 에 검증기를 추가하면 해당 컨트롤러에서는 검증기를 자동으로 적용
  • @InitBinder의 경우 해당 컨트롤러에만 영향을 주기 때문에 글로벌 설정을 별도로 해줘야함.

Validated를 추가해서 addItem 변경

    @PostMapping("/add")
    public String addItemV6(@Validated @ModelAttribute("item") Item item, BindingResult bindingResult,
                            RedirectAttributes redirectAttributes) {

        if(bindingResult.hasErrors()){
            log.info("target = {}",bindingResult.getTarget());
            return "validation/v2/addForm";
        }


        //성공 로직
        Item savedItem = itemRepository.save(item);
        redirectAttributes.addAttribute("itemId", savedItem.getId());
        redirectAttributes.addAttribute("status", true);
        return "redirect:/validation/v2/items/{itemId}";
    }
  • 검증대상 앞에 Validated를 붙여준다.
    • @Validated는 검증기를 실행하라는 어노테이션
    • 이 애노테이션이 붙으면 앞서 WebDataBinder에 등록한 검증기를 찾아서 실행
      • 만약 여기서 여러 검증기를 등록시 supported를 통해서 어떤 검증기가 실행되어야할지 구분이 된다.

글로벌 설정

@SpringBootApplication
public class ItemServiceApplication implements WebMvcConfigurer {

	public static void main(String[] args) {
		SpringApplication.run(ItemServiceApplication.class, args);
	}

	@Override
	public Validator getValidator() {
		return new ItemValidator();
	}

}

주의점

  • 글로벌 설정시 BeanValidator가 자동 등록이 되지 않기 때문에 위와 같이 사용을 하는 경우는 드물다.
profile
열심히하자
post-custom-banner

0개의 댓글