SpringBoot 백 엔 드 데이터 검증 JSR 303 사용 상세 설명

주해 만 보고 싶 으 면 글 의 끝 부분 으로 뛰 어 오 세 요.
간단 한 소개
앞 뒤 에서 데이터 인 터 랙 션 을 하 는 과정 에서 전단 에서 데 이 터 를 백 엔 드 로 전송 하기 전에 보통 한 번 검 사 를 하고 검사 가 성공 한 후에 야 데 이 터 를 백 엔 드 로 보 냅 니 다.그러나 우 리 는 서버 에서 데 이 터 를 한 번 더 검증 해 야 한다.요청 한 데 이 터 를 보 내 는 링크 는 쉽게 얻 을 수 있 기 때문에 전단 인터페이스 를 거치 지 않 고 postman 등 도 구 를 사용 하여 배경 에 데 이 터 를 직접 보 낼 수 있 기 때문에 보 낸 데 이 터 는 비합법적 인 상황 이 될 수 있 습 니 다.
프로젝트 생 성
우선 springboot 프로젝트 를 만 듭 니 다.
사용 하 는 spring boot 버 전 은 다음 과 같 습 니 다.

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.3.9.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
 </parent>
다음 의존 도입

 <dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-thymeleaf</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-devtools</artifactId>
   <scope>runtime</scope>
   <optional>true</optional>
  </dependency>
  <dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <optional>true</optional>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
   <exclusions>
    <exclusion>
     <groupId>org.junit.vintage</groupId>
     <artifactId>junit-vintage-engine</artifactId>
    </exclusion>
   </exclusions>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-validation</artifactId>
  </dependency>
 </dependencies>
이 표 지 는 새로운 spring boot 버 전에 서 단독으로 도입 해 야 합 니 다.이전 버 전에 서 는 기본적으로 도입 되 었 다.이것 은 jsr 303 주해 에 대한 지원 을 도입 하 는 데 쓰 인 다.

 <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-validation</artifactId>
  </dependency>
그리고 자바 빈 을 만 듭 니 다.

package cn.jxj4869.demo.entity;

import lombok.Data;

import javax.validation.constraints.NotNull;

@Data
public class User {
 @NotNull
 private Integer id;
 private String username;
 private String password;
 private String email;
}
형식의 자바 빈 을 되 돌려 줍 니 다.

package cn.jxj4869.demo.entity;

import java.util.HashMap;

public class R extends HashMap<String, Object> {
	private static final long serialVersionUID = 1L;

	public R() {
		put("code", 0);
		put("msg", "success");
	}


	public static R error(int code, String msg) {
		R r = new R();
		r.put("code", code);
		r.put("msg", msg);
		return r;
	}

	public static R ok(String msg) {
		R r = new R();
		r.put("msg", msg);
		return r;
	}

	public R put(String key, Object value) {
		super.put(key, value);
		return this;
	}
}
controller 를 만 듭 니 다.
index 방법 은 첫 페이지 로 넘 어 가 는 데 사 용 됩 니 다.

package cn.jxj4869.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
public class UserController {

 @RequestMapping("/")
 public String index(){
  return "index";
 }
}
홈 페이지 코드 는resources/templates디 렉 터 리 아래 에 놓 습 니 다.

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Title</title>
 <style>
  div{
   margin-top: 50px;
  }
 </style>
</head>
<body>

<div>
     
 <br><br>
 <form method="post">
  <label>   </label>
  <input type="text" name="username"/>
  <br>
  <label>  </label>
  <input type="text" name="password"/>
  <br>
  <label>  </label>
  <input type="email" name="email"/>
  <br>
  <input type="submit" value="  "/>
 </form>
</div>
<div>
     
 <br><br>
 <form method="post">
  <input type="hidden" name="id" value="1">
  <label>   </label>
  <input type="text" name="username"/>
  <br>
  <label>  </label>
  <input type="text" name="password"/>
  <br>
  <label>  </label>
  <input type="email" name="email"/>
  <br>
  <input type="submit" value="  "/>
 </form>
</div>

</body>
</html>
전통 적 인 검증 방식
백 엔 드 에서 데이터 검 사 를 하려 면 전통 적 인 검사 방식 은 controller 층 에서 데 이 터 를 받 은 후에 요구 에 따라 데 이 터 를 검사 합 니 다.
예 를 들 어 user bean 대상 을 받 아야 합 니 다.
현재 user 대상 의username속성 을 비공 식 검사 하고password속성 을 비공 식 검사 하고 길이 검 사 를 해 야 합 니 다.

 @PostMapping("/user")
 @ResponseBody
 public R user1(User user) throws Exception {
  if(StringUtils.isEmpty(user.getUsername())) {
   return R.error(400,"username    ");
  }
  if(StringUtils.isEmpty(user.getPassword())||user.getPassword().length()>8||user.getPassword().length() <4) {
   return R.error(400,"password  ");
  }
  return null;
 }
만약 에 여러 가지 방법 이 user 대상 을 받 아들 여야 하고 검증 해 야 하 는 속성 이usernamepassword두 가지 속성 에 그 치지 않 을 수 있 습 니 다.만약 에 모든 방법 에서 위 와 같은 검증 방식 을 사용 하면 코드 가 비대 하고 유지 하기 어 려 울 수 있 습 니 다.userbean 의 속성 을 바 꾸 거나 검증 규칙 을 수정 한 후에모든 검사 코드 를 업데이트 해 야 합 니 다.이것 은 공 사 량 이 매우 많은 일이 다.
JSR 303 사용 하기
상술 한 문 제 를 해결 하기 위해 서,우 리 는 JSR 303 이 제공 한 주 해 를 사용 하여 검사 할 수 있다.
JSR 은 자바 Specification Requests 의 줄 임 말로 자바 규범 제안 을 의미한다.JSR 303,즉 303 호 제안 입 니 다.
JSR 303 을 사용 하 는 방법 은 매우 간단 합 니 다.예 를 들 어 위의 수요,우 리 는 user 의 속성 에 주 해 를 추가 하면 됩 니 다.
절 차 는 다음 과 같다.
1.빈 에 게 검사 주 해 를 추가 합 니 다.보통javax.validation.constraints이 가방 에서 도 일부hibernate가 제공 합 니 다.
2.검증 기능@Valid 를 엽 니 다.
3.검사 에 실 패 했 을 때org.springframework.validation.BindException이상 을 던 집 니 다.
자주 사용 하 는 검사 주 해 는 문장 끝 에 있다.

package cn.jxj4869.demo.entity;

import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.NotNull;

@Data
public class User {

 private Integer id;
 @NotBlank
 private String username;
 @NotBlank
 @Length(min = 4,max = 8)
 private String password;
 private String email;
}
그리고 controller 안의 방법 에@Valid주 해 를 더 하면 됩 니 다.

 @PostMapping("/user2")
 @ResponseBody
 public R user2(@Valid User user) throws Exception {
  System.out.println(user);
  return null;
 }
검사 에 실패 하면 다음 과 같은 오류 가 발생 합 니 다.기본 알림 메 시 지 를 드 립 니 다.
在这里插入图片描述
사용자 정의 오류 정보
그럼 이 잘못된 메 시 지 는 어떻게 된 거 예요?@NotNULL주석 코드 에 들 어가 기

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
@Documented
@Constraint(validatedBy = { })
public @interface NotBlank {

	String message() default "{javax.validation.constraints.NotNull.message}";
	............
 ............
 ............
}
속성 이 하나message있 습 니 다.잘못된 힌트 내용 을 지정 한 것 이 분명 하 다.이 오류 알림 은validationMessages.properties라 는 파일 에서 아이디어 검색 도 구 를 사용 하여 찾 을 수 있 습 니 다.shift키 를 더 블 클릭 하여 검색 을 엽 니 다.
이렇게 많은validationMessages.properties문서 가 있 고 국제 화 를 지원 하 는 것 을 발견 했다.
在这里插入图片描述 validationMessages_zh.properties을 열 면 이렇게 많은 힌트 를 정의 하 는 것 을 볼 수 있 습 니 다.오류 알림 은 이 파일 에서 가 져 온 것 입 니 다.
在这里插入图片描述
기본 검사 알림 정 보 를 사용 하지 않 으 려 면 스스로 지정 할 수 있 습 니 다.
message 의 값 을 지정 하면 됩 니 다.

@NotBlank(message = "       ")
 private String username;
在这里插入图片描述
오류 정보 가 져 오기 및 응답
검사 가 잘못 되 었 을 때 오류 인 터 페 이 스 를 기본적으로 되 돌려 주거 나 오류 알림 의 json 데 이 터 를 되 돌려 줍 니 다.그러나 기본적으로 제공 하 는 것 은 우리 가 원 하 는 것 이 아니 라 잘못된 정 보 를 얻 을 수 있다 면 해당 데 이 터 를 사용자 정의 할 수 있 습 니 다.
잘못된 정 보 를 얻 는 방식 도 간단 하 다.방법 에BindingResult result이라는 인 자 를 추가 하면 잘못된 정 보 는 이 안에 포 함 될 것 이다.

@PostMapping("/user2")
 @ResponseBody
 public R user2(@Valid User user, BindingResult result) throws Exception {
  System.out.println(user);
  if(result.hasErrors()) { //       
   Map<String,String> map = new HashMap<>();
   //1、         
   result.getFieldErrors().forEach((item)->{
    //FieldError        
    String message = item.getDefaultMessage();
    //          
    String field = item.getField();
    map.put(field,message);
   });
   return R.error(400,"        ").put("data",map);
  }
  //      ,           。
  return null;
 }
그러나 위의 이런 방식 을 추천 하지 않 습 니 다.이 유 는 똑 같 습 니 다.검사 할 곳 이 많아 졌 습 니 다.모든 방법 에 이런 이상 처 리 를 더 하면 코드 가 비대 해 집 니 다.
springmvc 에 전역 적 인 이상 처리 가 있다 는 것 을 기억 하 시 는 지 모 르 겠 습 니 다.우 리 는 이상 처 리 를 사용자 정의 하여 이 안에서 이상 처 리 를 통일 할 수 있 습 니 다.
통일 처리BinException.이렇게 하면 controller 에서 잘못된 정 보 를 처리 하지 않 아 도 된다.

package cn.jxj4869.demo.execption;

import cn.jxj4869.demo.entity.R;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;


import java.util.HashMap;
import java.util.Map;

@RestControllerAdvice(basePackages = "cn.jxj4869.demo.controller")
public class MyExceptionControllerAdvice {

 @ExceptionHandler(value = BindException.class)
 public R handleVaildException(BindException e) {

   Map<String,String> map = new HashMap<>();
   //1、         
   e.getFieldErrors().forEach((item)->{
    //FieldError        
    String message = item.getDefaultMessage();
    //          
    String field = item.getField();
    map.put(field,message);
   });
   return R.error(400,"        ").put("data",map);

 }
}
오류 이상 유형 보충
오 류 를 검사 할 때 두 가지 이상 을 던 집 니 다.org.springframework.validation.BindException @Valid주 해 를 사용 하여 검사 할 때 던 진 것 입 니 다.org.springframework.web.bind.MethodArgumentNotValidException사용@validated검사 할 때 던 진 것
이상 포획 에 아래 이 걸 넣 으 세 요.

 @ExceptionHandler(value= MethodArgumentNotValidException.class)
 public R handleVaildException(MethodArgumentNotValidException e){

  BindingResult bindingResult = e.getBindingResult();

  Map<String,String> map = new HashMap<>();
  bindingResult.getFieldErrors().forEach((fieldError)->{
   map.put(fieldError.getField(),fieldError.getDefaultMessage());
  });
  return R.error(400,"        ").put("data",map);
 }
그룹 검사
서로 다른 업무 장면 에서 검사 규칙 은 다르다.예 를 들 어 user 대상id이라는 속성 은 새로 추 가 될 때 이 속성 은 채 우지 않 고 null 이 어야 하지만 수정 할 때id속성 은 null 이 될 수 없다.
주해 중의groups속성 으로 지정 할 수 있 으 며,어떤 상황 에서 개 주 해 를 사용 할 수 있 습 니까?

@Documented
@Constraint(validatedBy = { })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
public @interface NotBlank {

	Class<?>[] groups() default { };
	........
}
먼저 두 개의 인터페이스AddGroupUpdateGroup를 정의 하고 그 어떠한 실현 도 할 필요 가 없다.

package cn.jxj4869.demo.valid;

public interface UpdateGroup {
}

package cn.jxj4869.demo.valid;

public interface AddGroup {
}
user 에 group 을 지정 합 니 다.
  • id 속성 은 AddGroup 에 있 을 때 null 이 어야 합 니 다.UpdateGroup 에 있 을 때 null
  • 이 되 어 서 는 안 됩 니 다.
  • username 속성 은 AddGroup 과 Update 를 할 때 모두 검증 해 야 합 니 다.비어 있 으 면 안 됩 니 다.
  • password 속성 은 검사 할 때 그룹 을 지정 하면 작 동 하지 않 습 니 다.검사 할 그룹 을 지정 하지 않 았 기 때 문 입 니 다
  • 
    package cn.jxj4869.demo.entity;
    
    import cn.jxj4869.demo.valid.AddGroup;
    import cn.jxj4869.demo.valid.UpdateGroup;
    import lombok.Data;
    
    
    import javax.validation.constraints.NotBlank;
    import javax.validation.constraints.NotEmpty;
    import javax.validation.constraints.NotNull;
    import javax.validation.constraints.Null;
    
    
    @Data
    public class User {
    
     @Null(groups = {AddGroup.class})
     @NotNull(groups = {UpdateGroup.class})
     private Integer id;
     
     
     @NotBlank(message = "       ",groups = {AddGroup.class,UpdateGroup.class})
     private String username;
     @NotEmpty
     private String password;
     private String email;
    }
    controller 에서@Validated주석 을 사용 하여 검사 할 그룹 을 지정 합 니 다.
    
     @PostMapping("/user3")
     @ResponseBody
     public R user3(@Validated(UpdateGroup.class) User user) {
      System.out.println(user);
    
      return null;
     }
    결 과 는 다음 그림 에서 보 듯 이password속성 이 검사 할 그룹 을 지정 하지 않 았 기 때문에 검사 할 때 합 법성 검 사 를 하지 않 습 니 다.
    在这里插入图片描述
    在这里插入图片描述
    사용자 정의 검사
    제 공 된 주해 가 우리 의 요 구 를 만족 시 키 지 못 할 때 주 해 를 사용자 정의 할 수 있 습 니 다.
    예 를 들 어 우 리 는 현재 user 에 속성status을 추가 하고 이 속성의 값 은 0 또는 1 만 요구 합 니 다.
    새 주석@StatusValue을 만 듭 니 다.
    jsr 303 의 규범 에 따라 주 해 를 검사 하 는 데 세 가지 속성 이 있다.
  • message:잘못된 힌트 를 얻 기 위 한
  • groups:검사 그룹 을 지정 합 니 다.
  • payload:부하 정 보 를 사용자 정의 할 수 있 습 니 다
  • @Constraint주 해 를 사용 하여 이 주 해 를 지정 하 는 검사 기 를 사용 합 니 다.
    
    package cn.jxj4869.demo.valid;
    
    import javax.validation.Constraint;
    import javax.validation.Payload;
    import java.lang.annotation.Documented;
    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;
    import static java.lang.annotation.ElementType.*;
    import static java.lang.annotation.ElementType.TYPE_USE;
    import static java.lang.annotation.RetentionPolicy.RUNTIME;
    
    @Documented
    @Constraint(validatedBy = { StatusValueConstraintValidator.class })
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    @interface StatusValue {
     String message() default "{cn.jxj4869.valid.StatusValue.message}";
    
     Class<?>[] groups() default { };
    
     Class<? extends Payload>[] payload() default { };
    
     int[] value() default { };
    }
    사용자 정의 검사 기
    이 인 터 페 이 스 를 실현 해 야 합 니 다ConstraintValidator.첫 번 째 범 형 은 어떤 주 해 를 검사 해 야 하 는 지,두 번 째 범 형 은 검사 해 야 할 데이터 의 유형 입 니 다.
  • initialize초기 화 방법
  • isValid검사 방법,검사 성공 여 부 를 판단
  • 
    package cn.jxj4869.demo.valid;
    
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    import java.util.HashSet;
    import java.util.Set;
    
    public class StatusValueConstraintValidator implements ConstraintValidator<StatusValue,Integer> {
    
     private Set<Integer> set = new HashSet<>();
     //     
     @Override
     public void initialize(StatusValue constraintAnnotation) {
    
      int[] value = constraintAnnotation.value();
      for (int val : value) {
       set.add(val);
      }
    
     }
     /**
      *         
      * @param value
      * @param context
      * @return
      */
     @Override
     public boolean isValid(Integer value, ConstraintValidatorContext context) {
    
      return set.contains(value);
     }
    }
    마지막 으로resources디 렉 터 리 에ValidationMessages.properties파일 을 추가 합 니 다.
    오류 정 보 를 지정 하 는 데 사용 합 니 다.
    
    cn.jxj4869.valid.StatusValue.message=        
    UserBean
    
    @Data
    public class User {
    
     @Null(groups = {AddGroup.class})
     @NotNull(groups = {UpdateGroup.class})
     private Integer id;
    
    
     @NotBlank(message = "       ",groups = {AddGroup.class,UpdateGroup.class})
     private String username;
     @NotEmpty
     private String password;
     private String email;
    
     @StatusValue(value = {0,1},groups = {AddGroup.class,UpdateGroup.class})
     private Integer status;
    }
    在这里插入图片描述
    在这里插入图片描述
    상용 주해 집합
    주해
    기능.
    @Null
    대상 은 null 이 어야 합 니 다.
    @NotNull
    대상 이 null 이 아니 어야 합 니 다.길이 가 0 인 문자열 을 검사 할 수 없습니다.
    @NotBlank
    문자열 은 Null 이 아니 라 앞 뒤 공백 길 이 를 0 이상 제거 해 야 합 니 다.
    @NotEmpty
    문자열 이 비어 있어 야 합 니 다.
    @Length(min = 1,max = 50)
    문자열 은 지정 한 길이 안에 있어 야 합 니 다.
    @Range(min = 0,max = 100)
    지 정 된 범위 내 에서
    @AssertTrue
    대상 은 true 여야 합 니 다.
    @AssertFalse
    대상 은 false 여야 합 니 다.
    @Max(Value)
    숫자 여야 하 며,Value 보다 작 거나 같 아야 합 니 다.
    @Min(Value)
    숫자 여야 하 며,Value 보다 크 거나 같 아야 합 니 다.
    @DecimalMax(Value)
    숫자(BigDecimal)이 어야 하 며,Value 보다 작 거나 같 아야 합 니 다.소수 존재 정밀도
    @DecimalMin(Value)
    숫자(BigDecimal)이 어야 하 며,Value 보다 크 거나 같 아야 합 니 다.소수 존재 정밀도
    @Digits(integer,fraction)
    숫자(BigDecimal),integer 정수 정밀도,fraction 소수 정밀도 여야 합 니 다.
    @Size(min,max)
    대상(Array,Collection,Map,String)길 이 는 주어진 범위 에 있어 야 합 니 다.
    @Email
    문자열 은 합 법 적 인 메 일 주소 여야 합 니 다.
    @Past
    Date 와 Calendar 대상 은 현재 시간 전에
    @Future
    Date 와 Calendar 대상 은 현재 시간 이후 에
    @Pattern(regexp="정규")
    문자열 이 정규 표현 식 의 값 을 만족 시 킵 니 다.
    여기 서 SpringBoot 백 엔 드 에서 데이터 검증 JSR 303 의 사용 에 대한 상세 한 설명 을 소개 합 니 다.더 많은 SpringBoot 데이터 검증 JSR 303 의 사용 내용 은 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 부 탁 드 리 겠 습 니 다!

    좋은 웹페이지 즐겨찾기