MVC2 - Validation

2022. 9. 27. 00:17·Spring

상품 등록시의 검증

Validation Flow

정상 로직

PRG : POST - Redirect - GET

 

비정상 로직

예) 상품명을 입력하지 않거나, 숫자 필드에 문자가 들어오는 경우

컨트롤러에서 검증이 실패하면 검증에 실패한 정보를 담아서 등록 폼을 다시 렌더링한다.

컨트롤러에서 모델에 잘못된 데이터까지 다시 담아서 등록 폼에 다시 전달해야 한다.

어떤 값이 잘못되어 있는지 다시 알려 주어야 한다.

StringUtils : 문자열 관련 기능을 강화한 클래스

 

Validation 방법

타입 오류 처리하기

타입 오류는 컨트롤러 접근 전에 500 - BAD REQUEST로 발생한다.

타입 오류가 발생해도 오류가 폼에 남아야 하지만 바인딩이 처리되지 못함

 

BindingResult

검증 오류를 보관하는 객체. BindingResult를 빼면 컨트롤러에서 튕겨 400 오류를 발생시킴

만약 ModelAttribute에 매핑 오류가 생기게 되면, 일단 BindingResult에 담긴다.

 

BindingResult에 검증오류를 적용하려면?

1. 타입 오류의 경우 FieldError를 생성해서 BindingResult에 넣어준다.

2. 개발자가 직접 넣어준다

3. Validator 사용

 

필드 오류

FieldError(String ObjectName[@ModelAttribute 이름], String field[오류 발생 필드 이름], String defaultMessage)

FieldError(String ObjectName[@ModelAttribute 이름], String field[오류 발생 필드 이름], @Nullable Object rejectedValue, boolean bingingFailture[바인딩 실패인지, 검증 실패인지], @Nullable String[] codes[메시지 코드], @Nullable Object[] arguments[메시지에서 사용하는 인자], String defaultMessage[기본 오류 메시지])

rejectedValue에서 오류 발생시 값을 저장하게 됨

 

글로벌 오류

ObjectError(String ObjectName[@ModelAttribute 이름], @Nullable String[] codes[메시지 코드], @Nullable Object[] arguments[메시지에서 사용하는 인자], String defaultMessage[기본 오류 메시지])

 

@PostMapping("/add")
public String addItem(@ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) {

* BindingResult는 ModelAttribute 뒤에 와야 한다.

* Model에 담지 않아도 ModelAttribute에 함께 담긴다

 

타임리프와 함께 사용하기

#fields : #fields로 BindingResult에 접근

th:errors : 필드에 오류가 있는 경우에 태그 출력

th:errorclass : th:field 에서 지정한 필드에 오류가 있을 경우 class 정보를 추가

 

 

오류 메시지 처리

위의 FieldError, ObjectError의 인자(codes, arguments)를 활용한다

application.properties 수정하기

spring.messages.basename=messages,errors

messages.properties

required.item.itemName=상품 이름은 필수입니다.
range.item.price=가격은 {0} ~ {1} 까지 허용합니다.
max.item.quantity=수량은 최대 {0} 까지 허용합니다.

Controller 수정

bindingResult.addError(new FieldError("item", "itemName", item.getItemName(), false, new String[]{"required.item.itemName"}, null, null));

 

 

 

reject(), rejectValue()를 활용

BindingResult는 Target을 가지고 있다(위에서 ModelAttribute의 대상 객체)

bindingresult.getObjectName() | bindingResult.getTarget() 으로 확인가능

bindingResult.rejectValue("quantity", "max", new Object[]{9999}, null);
bindingResult.addError(new ObjectError("item", new String[]{"totalPriceMin.item"}, new Object[]{10000, resultPrice}, null));
bindingResult.reject("totalPriceMin", new Object[]{1000, resultPrice}, null);

rejectValue(errorcode, errorArgs, defaultMessage)

reject(field, errorcode, errorArgs, defaultmessage)

위와 같이 rejectValue, reject를 사용한다.

 

오류 메시지의 계층화

이미 정의된 메시지를 활용하기 위해서는 

단순한 메시지 : 여러 곳에서 사용이 가능하다(범용성👍)

세밀한 메시지 : 작성이 어렵다(범용성👎) - 객체명 + 필드명 조합

세밀한 메시지가 "없다면" 단순한 메시지를 출력하도록 하자

예 ) 객체명+필드명 메시지 확인 -> 없다면 범용적인 메시지 출력

메시지의 설계는 구체적인 것부터 덜 구체적인 것 순서로 만들자

 

MessageCodeResolver 사용

Spring에서 제공하는 MessageCodesResolver는 메시지 코드들을 생성한다.

DefaultMessageCodesResolver가 기본 구현체이다.

code+objectname+field
code+field
code+field type
code

순으로 메시지가 생성된다

 

스프링이 직접 만든 오류 메시지 처리

스프링에서 타입 오류가 발생하면 typemismatch가 나타난다.

typeMismatch.java.lang.Integer=숫자를 입력해주세요.
typeMismatch=타입 오류입니다.

위와 같이 계층화된 메시지를 활용해 보편적인 메시지, 세부적인 메시지를 작성해 주자!

 

Validator 분리

로직이 복잡해질 때, Validator를 빈으로 등록해 사용한다

Spring이 제공하는 Validator를 implement 받아 구현하자

@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;

WebDataBinder를 통해서 사용한다.

Controller 내부에 @InitBinder를 사용하여 커스텀한 Validator를 넣어주자

private final ItemValidator itemValidator;

@InitBinder
public void init(WebDataBinder dataBinder){
    dataBinder.addValidators(itemValidator);
}

위처럼 사용하면 init()이 선언된 컨트롤러가 호출될 때마다 validator를 생성해 준다.

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

검증을 진행할 ModelAttribute의 앞에 @Validated 어노테이션을 붙여주어야 한다.

 

저작자표시 비영리 변경금지 (새창열림)

'Spring' 카테고리의 다른 글

MVC2 - 로그인(쿠키, 세션)  (1) 2022.10.03
MVC2 - Bean Validation  (0) 2022.09.27
File->MultipartFile  (0) 2022.07.26
QueryDSL 사용 전 환경설정  (0) 2022.07.12
Reactive Programming  (0) 2022.06.30
'Spring' 카테고리의 다른 글
  • MVC2 - 로그인(쿠키, 세션)
  • MVC2 - Bean Validation
  • File->MultipartFile
  • QueryDSL 사용 전 환경설정
코드파고
코드파고
  • 코드파고
    Digging Code
    코드파고
  • 전체
    오늘
    어제
    • 분류 전체보기 (99)
      • Memorization (12)
      • Spring (18)
      • Java (1)
      • Algorithm (40)
      • Server (2)
      • DB (0)
      • CS (0)
      • CI & CD (4)
      • Architecture (0)
      • Design Patterns (0)
      • Study (1)
      • Book (9)
        • DEV (7)
        • Non-DEV (0)
      • Infra (1)
        • Kafka (6)
        • AWS (4)
      • TroubleShooting (1)
        • Etc (1)
      • Tools (0)
  • 블로그 메뉴

    • 홈
    • Github
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    architecture
    Spring
    클린아키텍쳐
    Spring Boot
    Spring독학
    SpringFramework
    Clean Code
    알고리즘
    clean architecture
    헥사고날아키텍쳐
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
코드파고
MVC2 - Validation
상단으로

티스토리툴바