IoT 빅데이터 응용 교육 과정_하계

[IoT 빅데이터 응용 교육 과정]23.07.10 13장 사용자 정의 애너테이션

연지양갱 2023. 7. 10. 15:01
728x90
반응형
SMALL

교재

스프링 코딩 공작소

https://thebook.io/080266/0472/

 

스프링 코딩 공작소: 13.3 사용자 정의 애너테이션으로 유효성 검사

더북(TheBook): (주)도서출판 길벗에서 제공하는 IT 도서 열람 서비스입니다.

thebook.io

 


사용자 정의 애너테이션 유효성 검사

JSR-380 제약 사항의 애너테이션으로는 중복 여부를 체크 할 수 없다.

사용자 정의 제약 사항을 선언할 수 있는 인터페이스 제공

 

 

 

1. 사용자 정의 애너테이션 선언

애너테이션 생성 : 제약 사항 및 구성 속성에 설정하는 @interface를 사용하여 사용자 정의 애너테이션을 생성

constraintValidator 구현체 생성 : 생성한 사용자 정의 애너테이션의 유효성 검사 클래스는 javax.validtaion.contstraintValidator인터페이스의 구현체로 생성한다

2. @Valid를 이용하여 유효성 검사

3. <form:errors> 태그로 오류 메시지 출력

 

 

 

사용자 정의 애너테이션 생성

생성 양식

@Constraint(validatedBy=유효성 검사 클래스.class)
@Target(속성)
@Retention(속성)
@Documented
public @interface 사용자 정의 애너테이션 이름 {
    String message() default "출력할 오류 메시지";
    Class<?>[] groups() default {};
    Class<?>[] payload() default {};
}

 

필수 속성 

message, groups, payload 총 3가지 이다.

속성 설명
message 유효성 검사에서 오류가 발생하면 반환되는 기본 메시지입니다.
groups 특정 유효성 검사를 그룹으로 설정합니다.
payload 사용자가 추가한 정보를 전달하는 값입니다.

 

@Documented는 자바 문서에 문서화 여부를 결정

@Retention은 애너테이션의 지속 시간을 설정

 

▼ 표 13-4 @Retention의 속성

속성 설명
Source 소스 코드까지만 유지합니다. 즉, 컴파일하면 해당 애너테이션 정보는 사라집니다.
Class 컴파일한 .class 파일에 유지합니다. 즉, 런타임을 할 때 클래스를 메모리로 읽어 오면 해당 정보는 사라집니다.
Runtime 런타임을 할 때도 .class 파일에 유지합니다. 사용자 정의 애너테이션을 만들 때 주로 사용합니다.

 

@Target은 필드, 메소드, 클래스 등 애너테이션을 작성하는 곳

▼ 표 13-5 @Target의 속성

속성 애너테이션 적용 시점
TYPE class, interface, enum
FIELD 클래스의 멤버 변수
METHOD 메서드
PARAMETER 메서드 인자
CONSTRUCTOR 생성자
LOCAL_VARIABLE 로컬 변수
ANNOTATION_TYPE 애너테이션 타입에만 적용
PACKAGE 패키지
TYPE_PARAMETER 제네릭 타입 변수( MyClass<T>)
TYPE_USE 어떤 타입에도 적용( extends, implements, 객체 생성할 때 등)

 

 

예제 코드

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 {};
}

 

 

 

 

ConstraintValidator 인터페이스의 구현체 생성

javax.validation.ConstraintValidator인터페이스의 구현체 생성

▼ 표 13-6 ConstraintValidator 인터페이스의 메서드

유형 설명
void initialize(A constraintAnnotation) 사용자 정의 애너테이션과 관련 정보를 읽어 초기화합니다. 이때 A는 사용자 정의 제약 사항을 설정합니다.
boolean isValid(T value, ConstraintValidatorContext context) 유효성 검사 로직을 수행합니다. value는 유효성 검사를 위한 도메인 클래스의 변수 값이고, context는 제약 사항을 평가하는 컨텍스트입니다.

 

예제 코드

package com.springmvc.chap13;

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

}

MemberIdValidator클래스를 사용하는 사용자 정의 애너테이션을 지정

도메인 클래스 Member의 멤버 변수 타입을 설정

initalize()메소드 @MemberId가 속성 값이 없기 때문에 구현 부분없이 메소드 선언만 한다.

isValid()메소드는 유효성 검사하면서 true, false값을 리턴

 

 

 

1. messages.properties 파일에 다음 메시지를 추가합니다.

<messages.properties>

BookId.NewBook.bookId = 도서ID가 이미 존재합니다.

2. Book 클래스에 bookId 속성에 대해 사용자 정의 제약 사항의 애너테이션을 선언합니다.

<Book.java>

package com.springmvc.domain;
...
import com.springmvc.validator.BookId;

public class Book {
    @BookId ➊
    @Pattern(regexp="ISBN[1-9]+")
    private String bookId;
    ...
}

BookId필드 선언

 

3. BookMarket/src/main/Java 폴더에 com.springmvc.validator 패키지를 생성합니다. 이 패키지에 BookId 클래스를 생성하고 다음 내용을 작성합니다.

<BookId>

package com.springmvc.validator;

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


@Constraint(validatedBy=BookIdValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BookId {


    String message() default "";
    Class<?>[] groups() default {};
    Class<?>[] payload() default {};
}

사용자 정의 애너테이션 @BookId는 METHOD, FIELD, ANNOTATION_TYPE이 정의

@BookId는 message(), groups(), payload가 필수로 필요하다

@Constraint(validatedBy=BookidValidator.class)를 참고? 한다.

 

 

4. com.springmvc.validator 패키지에 BookIdValidator 클래스를 생성하고 다음 내용을 작성합니다.

<BookIdValidator.java>

package com.springmvc.validator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.springframework.beans.factory.annotation.Autowired;
import com.springmvc.exception.BookIdException;
import com.springmvc.service.BookService;
import com.springmvc.domain.Book;

public class BookIdValidator implements ConstraintValidator<BookId, String> {

    @Autowired
    private BookService bookService;
    
    public void initialize(BookId constraintAnnotation) { // @BookId 정보 초기화 메서드 
   	
    }
    
    public boolean isValid(String value, ConstraintValidatorContext context) { 
       Book book;
        try {
            book = bookService.getBookById(value);
        } catch (BookIdException e) {
            return true;
        }
        if (book! = null) {
            return false;
        }
        return true;
    }
}

initialize를 통해서 BookId의 관련 정보를 읽어 초기화 작업 수행

isValid() 메소드는 도메인 클래스 Book의 bookid 속성 값을 읽어 유효성 검사 

 

bookService.getBookByid(value) : 

입력했던 값을 getBookById함수를 통해서 값을 확인

-> 입력 값(ID)이 없다면 null

try-catch문으로 확인한 뒤에 true/false값으로 리턴한다.

 

 

5. com.springmvc.controller 패키지의 BookController 클래스에서 유효성 검사를 위해 submitAddNewBook() 메서드의 매개변수 중에서 커맨드 객체에 @Valid가 선언되어 있는지, 오류 처리 내용이 작성되어 있는지 확인합니다.

=> 컨트롤러에서 유효성 검사 한 뒤에 view페이지 리턴 하기

 

BookController.java

package com.springmvc.controller;
...
import javax.validation.Valid;

@Controller
@RequestMapping("/books")
public class BookController {
    ...
    @PostMapping("/add")
    public String submitAddNewBook(@Valid @ModelAttribute("NewBook") Book book, BindingResult result) {
        if (result.hasErrors()) {
            return "addBook";
        }

        MultipartFile bookImage = book.getBookImage();
        ...
    }
    ...
}

 

6. addBook.jsp 파일에서 유효성 검사에 따른 오류 메시지를 출력할 수 있도록 다음 내용이 작성되어 있는지 확인합니다.

-> <form > 태그 삽입

<%@ page contentType="text/html; charset=utf-8" %>
    ...
            <div class="col-sm-3">
                <form:input path="bookId" class="form-control"/>
            </div>
            <div class="col-sm-6">
                <form:errors path="bookId" cssClass="text-danger"/>
            </div>
            ...

 

7. 서버 실행하고 값을 입력했을 때 오류 메시지가 나오는 지 확인하기

위 사진처럼

"도서 ID가 이미 존재합니다"

라는 오류 메시지가 나온다

 

 

 

13.4 validator 인터페이스로 유효성검사

 

인터페이스의 구현체 생성

@InitBinder 선언 메소드 추가

@Valid를 이용한 유효성 검사

<Form:errors>태그로 오류 메시지 출력

 

위 사진 공부하기

 

 

 

Validator 인터페이스의 구현체 생성

 

▼ 표 13-7 Validator 인터페이스의 메서드

메서드 설명
boolean supports(Class<?> clazz) 주어진 객체(class)에 대해 유효성 검사를 수행할 수 있는지 검사할 목적으로 사용됩니다.
void validate(Object target, Errors errors) 주어진 객체(target)에 대해 유효성 검사를 수행하고 오류가 발생하면 주어진 Errors 타입의 errors 객체에 오류 관련 정보를 저장합니다.

 

 

Errors : org.springframework.validation 패키지에서 제공

 

실습 실습

 

 

실습이 다임!

 

 

 

 

 

 

반응형