사용자 정의 애너테이션으로 유효성 검사
앞서 배운 JSR-380 제약 사항 애터네이션으로는 중복 여부 체크를 할 수 없습니다.
이 문제를 해결하기 위해 사용자 정의 애너테이션을 선언해줍니다.
예를 들어 웹에서 회원 관리 시 ID는 회원을 식별할 수 있는 속성입니다.
따라서 회원 가입을 할 때 ID는 반드시 중복 여부를 체크해주어야 합니다.
이를 위해서 사용자 정의 제약 사항을 이용한 유효성 검사를 실행해줍니다.
중복 여부 체크 뿐만 아니라 다양한 제약 사항을 만들 수 있습니다.
도메인 클래스의 멤버 변수에 선언할 사용자 정의 애너테이션인 @MemberId를 만드는
방법은 다음과 같습니다.
public class Member {
@MemberId
private String memberId;
//Setter()와 Getter() 메소드
}
사용자 정의 애너테이션 생성
사용자 정의 애너테이션을 생성하는 형식은 다음과 같습니다.
@Constraint(validateBy=유효성 검사 클래스.class)
@Target(속성)
@Retention(속성)
@Documented
public @interface 사용자 정의 애너테이션 이름 {
String message() default "출력할 오류 메시지";
Class<?>[] groups() default {};
Class<?>[] payload() default {};
}
사용자 정의 애너테이션을 만들 때 반드시 있어야 하는 필수 속성은
message, groups, payload입니다.
속성 | 설명 |
message | 유효성 검사에서 오류가 발생하면 반환되는 기본 메시지 |
groups | 특정 유효성 검사를 그룹으로 설정 |
payload | 사용자가 추가한 정보를 전달하는 값 |
@Document는 자바 문서에 문서화 여부를 결정합니다.
@Retention은 애너테이션의 지속 시간을 설정합니다.
속성 | 설명 |
Source | 소스 코드까지만 유지 컴파일하면 해당 애너테이션 정보는 사라짐 |
Class | 컴파일한 .class 파일에 유지 런타임을 할 때 클래스를 메모리로 읽어 오면 해당 정보 사라짐 |
Runtime | 런타임 할 때도 .class 파일에 유지 사용자 정의 애너테이션을 만들 때 주로 사용 |
@Target은 필드, 메소드, 클래스 등 애너테이션을 작성합니다.
속성 | 애너테이션 적용 시점 |
TYPE | class, interface, enum |
FIELD | 클래스의 멤버 변수 |
METHOD | 메소드 |
PARAMETER | 메소드 인자 |
CONSTRUCTOR | 생성자 |
LOCAL_VARIABLE | 로컬 변수 |
ANNOTATION_TYPE | 애너테이션 타입에만 적용 |
PACKAGE | 패키지 |
TYPE_PARAMETER | 제네릭 타입 변수 |
TYPE_USE | 어떤 타입에도 적용 |
@Constraint는 만들고자 하는 애너테이션이 어떤 클래스를 사용하여 유효성 검사를 할지 설정합니다.
다음은 이를 이용해서 사용자 정의 애너테이션인 @MemberId를 생성하는 예시입니다.
package com.springmvc.controller;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
@Constraint(validatedBy=MemberIdValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MemberId {
String message() default "아이디는 admin 입니다.";
Class<?>[] groups() default {};
Class<?>[] payload() default {};
}
@interface를 이용해서 사용자 정의 애너테이션을 만들었습니다.
여기서 @Constraint의 validatedBy 요소에 설정한 클래스로 유효성 검사를 실시합니다.
즉, ConstraintValidator 인터페이스의 구현체인 클래스를 이용합니다.
ConstraintValidator 인터페이스의 구현체 생성
사용자 정의 애너테이션 유효성 검사 클래스를 생성하기 위해서는
javax.validation.ConstraintValidator 인터페이스 구현체를 생성합니다.
이를 생성하기 위해 initialize()와 isValid() 메소드를 구현해줍니다.
유형 | 설명 |
void initialize(A constraintAnnotation) | 사용자 정의 애너테이션과 관련 정보를 읽어 초기화 A는 사용자 정의 제약 사항을 설정 |
boolean isValid(T value, ConstraintValidatorContext context) | 유효성 검사 로직을 수행 value는 유효성 검사를 위한 도메인 클래스의 변수 값 context는 제약 사항을 평가하는 컨텍스트 |
다음은 @Constraint의 validatedBy 요소에 설정한 유효성 검사 클래스 예시입니다.
이 클래스는 ConstraintValidator 인터페이스 구현체입니다.
package com.springmvc.controller;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class MemberIdValidator implements ConstraintValidator<MemberId, String>{
private Member member;
public void initialize(MemberId constraintAnnotation) {
}
public boolean isValid(String value, ConstraintValidatorContext context) {
if(value.equals("admin")) {
return false;
}
return true;
}
}
ConstraintValidator 인터페이스는 매개변수 두 개를 정의합니다.
첫 번째 매개변수는 MemberIdValidator 클래스를 사용하는 사용자 정의 애너테이션을 지정합니다.
두 번째 매개변수는 도메인 클래스인 Member의 멤버 변수 타입을 설정합니다.
initialize() 메소드는 사용자 정의 에너테이션 @MemberId가 속성 값이 없기 때문에
메소드만 선언해줍니다.
isValid() 메소드는 ConstraintValidator<MemberId, String>에서 두 번째 매개변수 타입으로 정의한
도메인 클래스의 멤버 변수 값을 읽어 유효성 검사를 수행합니다.
다음은 컨트롤러에 다음과 같이 작성해줍니다.
package com.springmvc.controller;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/exam02")
public class Example02Controller {
@RequestMapping(method=RequestMethod.GET)
public String showForm(Model model) {
model.addAttribute("member",new Member());
return "webpage13_02";
}
@RequestMapping(method=RequestMethod.POST)
public String submit(@Valid @ModelAttribute Member member, Errors errors) {
if(errors.hasErrors()) {
return "webpage13_02";
}
return "webpage13_result";
}
}
뷰 페이지도 다음과 같이 작성해줍니다.
<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<title>Validation</title>
</head>
<body>
<h3>유효성 검사</h3>
<form:form modelAttribute="member" method="post">
<p>아이디 : <form:input path="memberId"/> <form:errors path="memberId"/>
<p><input type="submit" value="확인" />
<input type="reset" value="취소"/>
</form:form>
</body>
</html>
이렇게 사용자 정의 애너테이션을 정의하고 활용하는 방법을 공부해봤습니다.
다음 번에는 실습 중인 도서 등록 페이지에서 적용하는 방법을 공부해보겠습니다.
'SPRING' 카테고리의 다른 글
[SPRING]#53 도서 쇼핑몰 구현 (유효성 검사6) (0) | 2024.02.17 |
---|---|
[SPRING]#52 도서 쇼핑몰 구현 (유효성 검사5) (0) | 2024.02.16 |
[SPRING]#50 도서 쇼핑몰 구현 (유효성 검사3) (0) | 2024.02.12 |
[SPRING]#49 도서 쇼핑몰 구현 (유효성 검사2) (0) | 2024.01.23 |
[SPRING]#48 도서 쇼핑몰 구현 (유효성 검사1) (0) | 2024.01.21 |