본문 바로가기
spring

[spring] @Valid를 이용한 validation 체크와 custom annotation으로 validation

by moonsiri 2020. 10. 31.
728x90
반응형

1. Valid annotation을 이용한 validation 체크

 

우선, VO 클래스의 필드에 Validation을 체크하도록 annotation을 설정합니다.

예) @NotEmpty, @Length

@Data
@EqualsAndHashCode(callSuper = false)
public class SiriVO extends PagingCommonVO {

	private long siriId;

	@NotEmpty(message = "제목을 입력해주세요.")
	@Length(min = 0, max = 100, message = "The maximum length of the title value is 100. ")
	private String title;
	
	@CodeValid(message = "사용여부를 선택해주세요.")  // Custom annotation
	private String useYn;
    
}

 

아래와 같이 add 메소드 파라미터에 @valid 어노테이션을 적용합니다.

그리고나서 BindingResult result.hasErrors() 조건문을 추가하여 Validation 에러가 발생할 경우 에러를 처리하는 코드를 작성합니다.

    @RequestMapping(value = "/add")
    @ResponseBody
    public Map<String, Object> add(@Valid SiriVO param, BindingResult result) {
        Map<String, Object> map = new HashMap<>();

        if (result.hasErrors()) { //VO 유효성체크시 에러 존재
            // 에러 처리 코드 작성
            String msg = CmnUtils.getErrMsgValidAnnotation(result, "\n");
            map.put('message', msg);
            map.put('success', false);
            return map;
        }

        // add 수행
    }
    // 오류 메세지 처리
	public static String getErrMsgValidAnnotation(BindingResult result, String msgSeperator) {
		StringBuilder message = new StringBuilder("");

		// Validation 오류 발생시
		if (result.hasErrors()) {
			List<FieldError> errors = result.getFieldErrors();
			int errSize = errors.size();
			for (int i = 0; i < errSize; i++) {
				message.append(errors.get(i).getDefaultMessage());
				if (i != errSize - 1) {
					message.append(msgSeperator);
				}
			}
		}

		return message.toString();
	}

 

 

 

@NotNull, @NotEmpty, @NotBlank 차이

 

@NotNull

  • CharSequence, Collection, Map or Array객체는 null 일 수 없지만 비어있을 수 있다.

@NotEmpty

  • CharSequence, Collection, Map or Array객체는 null이거나 비어있을 수 없다.

@NotBlank

  • 문자열이 null이 아니며 길이가 0보다 크다.

 

import javax.validation.constraints.*;
String test = null;
@NotNull: false
@NotEmpty: false
@NotBlank: false

String test = "";
@NotNull: true
@NotEmpty: false
@NotBlank: false

String test = " ";
@NotNull: true
@NotEmpty: true
@NotBlank: false

String name = "Some text";
@NotNull: true
@NotEmpty: true
@NotBlank: true

 

 

 

2. Validation을 위한 Custom annotation 생성

 

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 특정code 허용체크
 */
@Target({ElementType.METHOD, ElementType.FIELD})  // 메소드와 필드에 사용
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CodeValidator.class)
public @interface CodeValid {  // Custom annotion CodeValid
	String message() default "invalid.";
    
	String[] codes() default {"Y", "N"}

	Class<?>[] groups() default {};

	Class<? extends Payload>[] payload() default {};
}

 

@Target

  • VO 전체를 대상으로 하려면 ElementType을 Type(Class)으로 정의하면된다. 여기선 필드 대상이기 때문에 METHOD와 FIELD를 정의한다.

@Retention

  • 유효성 검사는 런타임시에 진행되어야하기 때문에 RetentionPolicy를 런타임으로 정의한다.

@Constraint

  • @Valid를 통한 유효성 검사를 위해선 @Contraint가 정의된 객체여야하고, 실제 Validation을 하는 서비스 클래스를 같이 정의해 주어야 한다. (ex. CodeValidator.java)

 

import org.apache.commons.lang3.ArrayUtils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

/**
 * 특정 code 체크 Validator
 */
public class CodeValidator implements ConstraintValidator<CodeValid, String> {

	private static String[] ALLOW_ARRAY;

	@Override
	public void initialize(CodeValid constraintAnnotation) {
		this.ALLOW_ARRAY = constraintAnnotation.codes(); // 허용할 코드 설정
	}

	@Override
	public boolean isValid(String value, ConstraintValidatorContext context) {
		if (value == null) {
			return false;
		}

		if (ArrayUtils.contains(ALLOW_ARRAY, value)) {
			return true;
		}

		return false;
	}

}

 

@Getter
@Setter
@NoArgsConstructor
public class CodeVO {
	@CodeValid(codes = { "ACODE", "BCODE", "DCODE" })
	private String code;
}

 

 

 

3. @Valid 어노테이션을 사용하지 않고 로직에서 Validation

import javax.validation.Validator;

@Resource
private Validator validator;

Set<ConstraintViolation<SiriVO>> violations = validator.validate(siriVO);
if (!violations.isEmpty()) {
	throw new IllegalArgumentException();
}
728x90
반응형

댓글