티스토리 뷰

1. Custom Validation Rule 만들기

여기서의 핵심은 annotation을 직접 만드는 방법이라 생각한다.  아래 코드에 대하여 어노테이션 생성시 설정해줘야 하는 것들에 대해서, 좀더 자세하게는 자바 스터디 어노테이션 관련 파트에서 정리하겠다.

 

 

(1) Custom validation rule이란

이때까지는 Spring에서 제공하는 이미 정의된 validation rule을 사용하여 적용시켜서 유효성 검사를 진행했었다. (@Max, @Min ...)

하지만 유효성을 이미 만들어져 있는 rule에 벗어나는 경우, 만들어서 사용할 수 있는데, custom Java annotation을 만들고 custom business logic, rule을 만들어서 적용할 수 있다.

 

(2) Development Process

 - 내가 만든 business rule에 근거한 custom validation을 만드는데, Course Code가 반드시 "LUV"로 시작하게끔 만들 것이다.

 - @CourseCode라는 annotation을 직접 만들어 적용시킬것이고, Spring MVC가 내가 만든 custom validation rule을 불러 통과 시킬지 말지에 대한 boolean 값을 반환시켜 줄 것이다. (true, false)

 

 1) custom validation rule을 만든다

   a) @CourseCode annotation을 만든다 

   b) CourseCodeConstraintValidator(validation을 위한 custom business logic이 있는곳으로 true, false를 결정함)을 만든다.

 2) Customer class에 validation rule을 적용한다.

 3) HTML form에 에러 메세지를 표시한다.

 4) confirmation page를 업데이트 한다.

 

(3) 코드 예시

1) a) @CourseCode annotation을 만든다.

package com.luv2code.springdemo.mvc.validation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Constraint(validatedBy = CourseCodeConstraintValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD } ) // method나 field에 이 어노테이션을 적용할 수 있다.
@Retention(RetentionPolicy.RUNTIME) // how long will the marked annotation be stored or used?
// retain this annotation in the byte code and also use it at Runtime by the JVL

public @interface CourseCode {

	// define default course code
	public String value() default "LUV";
	
	// define default error message
	public String message() default "must start with LUV";
	
	// define default groups : group validation constraints together
	public Class<?>[] groups() default {};
	
	// define default payloads : give additional information about the validation error
	public Class<? extends Payload>[] payload() default {};
}

 - @Constraint(validatedBy = CourseCodeConstraintValidator.class)는 business logic이 CourseCodeConstraintValidator.class에 있다는것을 알려준다.

 - @Target : 어디에 annotation을 적용할 것인지, 이 annotation을 어디에 list할지 알려주는것이다. 

 - @Retention : 얼마나 annotation을 유지해야 하는지.

 - RetentionPolicy.RUNTIME : 컴파일된 java bytecode로 이 annotation을 유지해 JVM에 의한 runtime동안에 사용할 수 있다. 

 - value()는 @CourseCode를 사용시 @CourseCode(value="LUV" ..)랑 match되는것이고 message() @CourseCode(message="must start with LUV" ..)랑 매치 되는것이다. 그것의 default값을 설정해 준것은 @CourseCode를 사용시 customizable하게 만들기 위해서. 예를들어 @CourseCode(value="abc" message="~")라고 설정해준다면 value()와 message()가 바뀌게 되어 abc로 시작해야하고 그렇지 않으면 ~라는 에러메세지가 표시된다.

 - groups()를 설정해주는 것은 관련된 constraints를 그룹화 할 수 있는것이다.

 - payload()를 설정해 주는것은 validation 실패시에 custom detail을 제공한다.

 

1) b) CourseCodeConstraintValidator(validation을 위한 custom business logic이 있는곳으로 true, false를 결정함)을 만든다.

package com.luv2code.springdemo.mvc.validation;

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

public class CourseCodeConstraintValidator 
	implements ConstraintValidator<CourseCode, String> {
	
	// define a course Prefix that we can validate against
	private String coursePrefix;
	
	
	@Override 
	public void initialize(CourseCode theCourseCode) {
		coursePrefix = theCourseCode.value();		
	}
	
	@Override
	public boolean isValid(String theCode, ConstraintValidatorContext theConstraintValidatorContext) {
		// thecode : HTML form data entered by the user
		// theConstraintValidatorContext : 추가적인 error message를 여기에 배치할 수 있다.
		
		boolean result;
		
		if (theCode != null) {
			result = theCode.startsWith(coursePrefix);
		}else {
			result = true; // 이 필드는 required가 아니기때문에 아무것도 입력안하면 통과시키기
		}
		// need to check for null. 아무것도 입력하지않는 null일때를 처리해줘야한다.
		
		return result;
	}

}


 - 1) a)에서 @Constraint통해서 business logic이 있는 CourseCodeConstraintValidator 클래스를 표기하였다.

CourseCodeConstraintValidator를 만들어주고 ConstraintValidator인터페이스를 implement받는데, ConstraintValidator<annotation, 타입>로 표현된다. annotation으로 만든 CourseCode를 적고, Course Code필드는 String을 입력받으므로 타입에는 String을 적는다.

 - coursePrefix를 만들어 유효성을 검사할 대상을 만든다. 따라서 initialize method를 재정의 하여 CourseCode에서 value()를 통해 설정된 시작해야하는 문자열을 가지고 온다.
 -  isValid()에는 business logic이 놓이게 되는데, theCode에는 유저가 입력한 HTML form data가 오게되고, ConstraintValidatorContext객체에는 추가적인 에러메세지를 배치하여 사용할 수 있다.

 - isValid()안에서는 내가 하고싶은대로 마음대로 business logic을 만들면 된다. 위에서는 Course Code 필드는 required가 아니기때문에 null은 true를 반환하여 통과시킨다. 하지만 coursePrefix로 설정한 문자열과 일치하지 않으면 false를 반환하여 에러메세지를 보이게 된다.

 

2), 3), 4) 번은 지난번 예제와 동일하다.

최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday