<!-- springmvc 依赖-->
<dependency>
<groupId>com.github.fashionbrot</groupId>
<artifactId>validation-spring</artifactId>
<version>3.0.1</version>
</dependency>
implementation 'com.github.fashionbrot:validation-spring:3.0.1'
@Component
@Configuration
//localeParamName="lang" 开启国际化
//springProfilesActive="prod" springboot启动的环境
//@EnableValidatedConfig 开启validation 功能
@EnableValidatedConfig(localeParamName="lang",springProfilesActive="prod")
public class ValidConfig {
}
package com.github.fashionbrot.exception;
import com.github.fashionbrot.constraint.Violation;
import com.github.fashionbrot.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(ValidatedException.class)
@ResponseStatus(HttpStatus.OK)
public Object ValidatedException(ValidatedException e) {
List<Violation> violations = e.getViolations();
if (ObjectUtil.isEmpty(violations)){// 快速失败抛出异常信息
return e.getMsg();
}else {
return violations.stream().map(m -> m.getMsg()).collect(Collectors.joining(","));// 慢速失败抛出异常信息
}
}
}
@RequestMapping("/expression")
@RestController
public class ExpressionController {
@GetMapping("/test1")
@ResponseBody
@Validated(failFast = false) //开启参数验证
public String test1(Integer type,
@NotEmpty(expression = "type!=null and type==1 and springProfilesActive=='prod'",msg = "验证码不能为空") String smsCode,
@NotEmpty(expression = "type!=null and type==2 and springProfilesActive=='default'",msg = "密码不能为空") String password){
return "ok";
}
@GetMapping("/test2")
@ResponseBody
@Validated(failFast = false)//开启参数验证
public String test2( ExpressionEntity expression){
return expression.toString();
}
@GetMapping("/test3")
@ResponseBody
@Validated(failFast = false)//开启参数验证
public String test3( Default1Entity entity){
return entity.toString();
}
@Data
//@ValidatedParam("expression")//没有注解默认读取类名首字母小写,例如expressionEntity.type ; 有改注解则表达式中使用例如: expression.type
public class ExpressionEntity {
private Integer type;
//如果expression 条件=true,则进行@NotEmpty的验证
@NotEmpty(expression = "expressionEntity.type!=null and expressionEntity.type==1 and springProfilesActive=='prod'" ,msg = "验证码不能为空")
private String smsCode;
//如果expression 条件=true,则进行@NotEmpty的验证
@NotEmpty(expression = "expressionEntity.type!=null and expressionEntity.type==2 and springProfilesActive=='default'",msg = "密码不能为空")
private String password;
}
}
<!-- springboot 依赖-->
<dependency>
<groupId>com.github.fashionbrot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>3.0.1</version>
</dependency>
#springboot 依赖
implementation 'com.github.fashionbrot:spring-boot-starter-validation:3.0.1'
# 开启国际化 优先header读取lang,其次读取参数lang
validated.locale-param-name=lang
package com.github.fashionbrot.exception;
import com.github.fashionbrot.constraint.Violation;
import com.github.fashionbrot.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(ValidatedException.class)
@ResponseStatus(HttpStatus.OK)
public Object ValidatedException(ValidatedException e) {
List<Violation> violations = e.getViolations();
if (ObjectUtil.isEmpty(violations)){// 快速失败抛出异常信息
return e.getMsg();
}else {
return violations.stream().map(m -> m.getMsg()).collect(Collectors.joining(","));// 慢速失败抛出异常信息
}
}
}
/**
* @author fashionbrot
*/
@RestController
@RequestMapping("/vrv")
public class ValidReturnValueController {
@GetMapping("test1")
@Validated(failFast = false,validReturnValue = true)// 开启参数验证,failFast = false全部校验后抛出异常,validReturnValue = true 验证返回值
public ValidReturnValueEntity test1(Integer type){
return ValidReturnValueEntity.builder().type(type).build();
}
}
方法 | 默认值 | 说明 |
---|---|---|
Class<?>[] groups() default { } | {} | 校验组 |
boolean failFast() default true | true | true 快速失败 |
boolean validReturnValue() default false | false | 验证返回值 默认false |
注解 | 作用类型 | 注解说明 |
---|---|---|
AssertFalse | boolean、String | 只能为false |
AssertTrue | boolean String | 只能为true |
BankCard | String、CharSequence | 验证银行卡 |
CreditCard | String、CharSequence | 验证信用卡 |
IdCard | String、CharSequence | 验证身份证 |
String、CharSequence | 验证邮箱格式 | |
Digits | String、CharSequence | 验证是否是数字 |
Default | BigDecimal、BigInteger、Short、Integer、Long、Float、Double、String、CharSequence | 给属性设置默认值 |
Length | String、CharSequence | 验证字符串长度 |
Max | Long、Integer、Short、Float、Double、BigDecimal、BigInteger | 验证属性值不能大于设定值 |
Min | Long、Integer、Short、Float、Double、BigDecimal、BigInteger | 验证属性值不能小于设定值 |
NotBlank | String、CharSequence | 元素值不为空 |
NotEmpty | String、CharSequence、Collection、Map、Array | 验证对象不为空 |
NotEqualLength | String、CharSequence、Collection、Map、Array | 验证对象长度必须是设定值 |
NotNull | Object | 验证对象不能为空 |
Pattern | String、CharSequence | 验证正则表达式 |
Phone | String、CharSequence | 验证手机号格式 |
Range | BigDecimal、BigInteger、Short、Integer、Long、Float、Double | 验证属性值必须在 设定值之间 |
Contain | BigDecimal、BigInteger、Short、Integer、Long、Float、Double、String、CharSequence | 验证属性值包含设定值 |
Size | Collection、Map、Array | 验证集合、数组 size 在设定值值之间 |
方法名 | 示例 | 方法说明 |
---|---|---|
Class<?>[] groups() default {} |
@NotNull(msg = "不能为空", groups = {InsertGroup.class}) |
用于分组校验,指定注解适用的校验组,例如 InsertGroup.class ,以便在特定场景下执行相应的校验逻辑 |
String msg() default "${validated.Length.msg}"; |
@NotNull(msg = "不能为空") |
指定在验证失败时显示的错误消息内容 |
String expression() default "" |
@NotEmpty(expression = "type!=null and type==1 and springProfilesActive=='prod'", msg = "验证码不能为空") String smsCode |
当 expression 条件为 true 时,执行 @NotEmpty 验证,适用于基于表达式的条件校验;表达式语法和mybatis xml if 中表达式语法一样 |
package com.github.fashionbrot.constraint;
import java.lang.annotation.*;
@Documented
@Target({ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraint {
/**
* 属性 参数 实现接口
* @return Class
*/
Class<? extends ConstraintValidator<? extends Annotation, ?>>[] validatedBy() default {};
}
package com.github.fashionbrot.constraint;
import java.lang.annotation.Annotation;
/**
* 自定义注解实现接口,调用顺序 isValid,modify
* @param <A> Annotation
* @param <T> T
*/
public interface ConstraintValidator<A extends Annotation, T> {
/**
* annotation all 返回false 抛出异常
* @param annotation annotation
* @param value value
* @param valueType valueType
* @return boolean
*/
boolean isValid(A annotation, T value,Class<?> valueType);
/**
* 修改 value 值,常用于 加密解密字段、脱敏字段 、动态给定默认值、及各种自定义逻辑
* @param annotation annotation
* @param value value
* @param valueType valueType
* @return T
*/
default T modify(A annotation,T value,Class<?> valueType){
return value;
}
}
package com.github.fashionbrot.annotation;
import com.github.fashionbrot.constraint.Constraint;
import com.github.fashionbrot.constraint.CustomAnnotationConstraintValidator;
import java.lang.annotation.*;
@Documented
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {CustomAnnotationConstraintValidator.class}) //实现类
public @interface CustomAnnotation {
boolean modify() default true;//自己定义
String defaultValue() default "";//自己定义
/**
* 固定方法 验证失败返回的错误信息
* @return
*/
String msg() default "validated.AssertTrue.msg";
/**
* 固定方法 验证组
* default @see com.github.fashionbrot.groups.DefaultGroup
* @return groups
*/
Class<?>[] groups() default {};
}
package com.github.fashionbrot.constraint;
import com.alibaba.fastjson2.JSON;
import com.github.fashionbrot.TestEntity;
import com.github.fashionbrot.annotation.CustomAnnotation;
import com.github.fashionbrot.util.ObjectUtil;
public class CustomAnnotationConstraintValidator implements ConstraintValidator<CustomAnnotation, Object> {
//TODO 自定义注解可以注入spring 容器 bean
@Resource
private Environment environment;
@Override
public boolean isValid(CustomAnnotation annotation, Object value, Class<?> valueType) {
//可根据自己逻辑进行拦截
return true;
}
@Override
public Object modify(CustomAnnotation annotation, Object value, Class<?> valueType) {
if (annotation.modify() && value==null){
if (ObjectUtil.isNotEmpty(annotation.defaultValue())){
TestEntity entity = JSON.parseObject(annotation.defaultValue(), TestEntity.class);
return entity;
}else{
//可以根据需求动态修改
//TODO 比如加密解密、数据脱敏、增加默认值 等等
if (valueType == TestEntity.class){
TestEntity entity = new TestEntity();
entity.setId(2L);
entity.setName("李四");
return entity;
}
}
}
return value;
}
}
@Controller
public class Controller1{
@Validated(failFast = false)//TODO 添加该注解开启参数验证
public void test(@CustomAnnotation(defaultValue = "{\"id\":1,\"name\":\"张三\"}",modify = true) TestEntity test){
}
}
# 开启国际化 优先header读取lang,其次读取参数lang
validated.locale-param-name=lang
#valid_ru_RU.properties
validated.NotEmpty.msg= `не должно быть пустым
#####在我们header 中可以配置参数 lang=ru_RU 并且msg等于默认的${validated.NotEmpty.msg}
lang=ru_RU msg=${validated.NotEmpty.msg} 则会提示:`не должно быть пустым`
lang=zh_CN msg=${validated.NotEmpty.msg} 则会提示:`不能为空`
lang=en_US msg=${validated.NotEmpty.msg} 则会提示:`must not be empty`