代码简洁之道 beanvalidation
与 hibernate-validator
序言
beanvalidation官网:https://beanvalidation.org/ api的接口
Hibernate-validator官网:http://hibernate.org/validator/ api的实现
import lombok.Data;
import java.time.LocalDateTime;
/**
* 用户信息
*
* @author zs
* @date 2022-09-06
*/
@Data
public class UserInfo {
private Long id;
/**
* 不能是null, "", " "
*/
private String name;
/**
* 正整数, 1-800
*/
private Integer age;
/**
* email的格式
*/
private String email;
/**
* 符合中国大陆手机号
*/
private String phone;
/**
* 不能超过当前日期
*/
private LocalDateTime birthday;
/**
* url
*/
private String personalPage;
}
public class TraditionalTest {
@Test
public void test01(){
UserInfo userInfo = new UserInfo();
validateUserInfo(userInfo);
}
private static void validateUserInfo(UserInfo userInfo){
// 用户名校验
String name = userInfo.getName();
if (name == null || "".equals(name) || "".equals(name.trim())) {
//不符合校验规则
throw new RuntimeException("name 不符合校验规则");
}
// age校验
Integer age = userInfo.getAge();
boolean ageValidate = age > 1 && age < 800;
if (!ageValidate) {
throw new RuntimeException("age不符合校验规则,应在(1-800)");
}
//......
}
}
jdk自带了一些常用的javaee规范,对于没有自带的如果想要使用就需要自己引用了,比如beanvalidation
如何制定?
jcp官网:https://jcp.org/en/home/index
Jsr:JavaSpecification Requests java规范提案, 如beanvalidation的提案有如下3个。
提案号 | beanvalidation版本 |
---|---|
jsr303 | beanvalidation1.0 |
jsr349 | beanvalidation1.1 |
Jsr380 | beanvalidation2.0 |
javax走向jakarta
参考:https://blogs.oracle.com/theaquarium/opening-up-java-ee oracle把javaee规范捐献给eclipse基金会
不要和Apache的jakarta混为一谈
2011退休了:https://jakarta.apache.org/
<dependency>
<groupId>org.hibernate.validatorgroupId>
<artifactId>hibernate-validatorartifactId>
<version>7.0.1.Finalversion>
dependency>
<dependency>
<groupId>org.apache.tomcat.embedgroupId>
<artifactId>tomcat-embed-elartifactId>
<version>10.0.22version>
dependency>
package com.zs.validation;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class ValidationUtil {
//线程安全的 http://www.360doc.com/content/16/0222/17/16926569_536478632.shtml
private static Validator validator;
static {
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
public static List<String> valid(Object obj) {
//如果被校验对象 没有校验通过,则set里面就有校验信息
Set<ConstraintViolation<Object>> set = validator.validate(obj);
List<String> list = set.stream().map(v -> "属性:" + v.getPropertyPath() + ",属性的值" +
v.getInvalidValue() + ",校验不通过的提示信息:" + v.getMessage())
.collect(Collectors.toList());
return list;
}
}
添加注解
import jakarta.validation.constraints.NotNull;
@Data
public class UserInfo {
/**
* 不能是null, "", " "
*/
@NotNull
private String name;
测试
@Test
public void test01(){
UserInfo userInfo = new UserInfo();
userInfo.setAge(2);
// userInfo.setName("zs");
// validateUserInfo(userInfo);
List<String> list = ValidationUtil.valid(userInfo);
System.out.println(list);
}
[属性:name,属性的值null,校验不通过的提示信息:不能为null]
spi机制
@Null 被注释的元素必须为null
@NotNull 被注释的元素必须不为null
@NotEmpty 被注释的集合(size > 0)/字符串(!=null && !"")
@NotBlank !=null && !"" && !" "
@AssertTrue 被注释的元素必须为true
@AssertFalse 被注释的元素必须为false
@Min(value) 被注释的元素必须是一个数字,>=
@Max(value) 被注释的元素必须是一个数字,<=
@DecimalMin(value) >=
@DecimalMax(value) <=
@Size(max,min) 被注释的元素的大小必须在指定的范围内
@Digits(integer,fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@PastOrPresent 时间
@NegativeOrZero <=0
@Future 被注释的元素必须是一个将来的日期
@Pattern(value) 被注释的元素必须符合指定的正则表达式
@Email 被注释的元素必须是电子邮箱地址
@Length 被注释的字符串的大小必须在指定的范围内
@Range 被注释的元素必须在适合的范围内
@URL 一个url
/**
* 不能是null, "", " "
*/
@NotBlank
// @NotNull
// @NotEmpty
private String name;
/**
* 正整数, 1-800
*/
// @Min(1) @Max(800)
@Range(min=1,max=800)
private Integer age;
/**
* email的格式
*/
@NotBlank
@Email
private String email;
/**
* 符合中国大陆手机号
*/
@Pattern(regexp = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\d{8}$")
private String phone;
/**
* 不能超过当前日期
*/
@NotNull
@Past
private LocalDateTime birthday;
/**
* url
*/
@URL
private String personalPage;
package com.zs.validation.bean;
import jakarta.validation.constraints.*;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import org.hibernate.validator.constraints.URL;
import java.time.LocalDateTime;
/**
* 用户信息
*
* @author zs
* @date 2022-09-06
*/
@Data
public class UserInfo {
private Long id;
/**
* 不能是null, "", " "
*/
@NotBlank
// @NotNull
// @NotEmpty
private String name;
/**
* 正整数, 1-800
*/
// @Min(1) @Max(800)
@Range(min=1,max=800)
private Integer age;
/**
* email的格式
*/
@NotBlank
@Email
private String email;
/**
* 符合中国大陆手机号
*/
@Pattern(regexp = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\d{8}$")
private String phone;
/**
* 不能超过当前日期
*/
@NotNull
@Past
private LocalDateTime birthday;
/**
* url
*/
@URL
private String personalPage;
}
测试
package com.zs.validation;
import com.zs.validation.bean.UserInfo;
import org.junit.Test;
import java.time.LocalDateTime;
import java.util.List;
public class TraditionalTest {
@Test
public void test01(){
UserInfo userInfo = new UserInfo();
userInfo.setAge(1);
userInfo.setName("zs");
userInfo.setEmail("aaaa@qq.com");
userInfo.setPhone("13516466501");
userInfo.setBirthday(LocalDateTime.now().minusDays(1));
userInfo.setPersonalPage("http://www.baidu.com");
// validateUserInfo(userInfo);
List<String> list = ValidationUtil.valid(userInfo);
System.out.println(list);
}
private static void validateUserInfo(UserInfo userInfo){
// 用户名校验
String name = userInfo.getName();
if (name == null || "".equals(name) || "".equals(name.trim())) {
//不符合校验规则
throw new RuntimeException("name 不符合校验规则");
}
// age校验
Integer age = userInfo.getAge();
boolean ageValidate = age > 1 && age < 800;
if (!ageValidate) {
throw new RuntimeException("age不符合校验规则,应在(1-800)");
}
//......
}
}
@NotNull
NotNullValidator 类校验 NotNull注解
同理 @Xxx注解的校验器类为XxxValidator
org.hibernate.validator.internal.metadata.core.ConstraintHelper
if (enabledBuiltinConstraints.contains(BuiltinConstraint.JAKARTA_VALIDATION_CONSTRAINTS_NOT_BLANK)) {
putBuiltinConstraint(tmpConstraints, NotBlank.class, NotBlankValidator.class);
}
private boolean isBuiltinConstraint(Class extends Annotation> annotationType) {
return BuiltinConstraint.isBuiltin(annotationType.getName());
}
注意:一个注解约束可能对应多个约束Validator,如@NotEmpty
@NotBlank(message = "你的名字不能为空")
private String name;
@Min(value = 18,message = "你的名字小于{value},禁止进入")
private Integer age;
public static List<String> valid(Object obj) {
//如果被校验对象 没有校验通过,则set里面就有校验信息
Set<ConstraintViolation<Object>> set = validator.validate(obj);
List<String> list = set.stream().map(v ->
"属性:" + v.getPropertyPath() +
",属性的值" + v.getInvalidValue() +
",校验不通过的提示信息:" + v.getMessage() +
",消息模板(为被替换的提示信息):" + v.getMessageTemplate()
)
.collect(Collectors.toList());
return list;
}
@Data
public class UserInfo {
public interface Add { }
public interface Update { }
// 默认的组: jakarta.validation.groups.Default
@Null(groups = {Add.class, Default.class}) // 只用于新增
@NotNull(groups = Update.class)// 用于修改
private Long id;
@NotBlank(message = "你的名字不能为空")
private String name;
package com.zs.validation;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class ValidationUtil {
//线程安全的 http://www.360doc.com/content/16/0222/17/16926569_536478632.shtml
private static Validator validator;
static {
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
public static List<String> valid(Object obj,Class<?>... groups) {
//如果被校验对象 没有校验通过,则set里面就有校验信息
Set<ConstraintViolation<Object>> set = validator.validate(obj,groups);
List<String> list = set.stream().map(v ->
"属性:" + v.getPropertyPath() +
",属性的值" + v.getInvalidValue() +
",校验不通过的提示信息:" + v.getMessage() +
",消息模板(为被替换的提示信息):" + v.getMessageTemplate()
)
.collect(Collectors.toList());
return list;
}
}
测试
@Test
public void test01(){
UserInfo userInfo = new UserInfo();
userInfo.setAge(1);
userInfo.setName("zs");
userInfo.setEmail("aaaa@qq.com");
userInfo.setPhone("13516466501");
userInfo.setBirthday(LocalDateTime.now().minusDays(1));
userInfo.setPersonalPage("http://www.baidu.com");
List<String> list = ValidationUtil.valid(userInfo, UserInfo.Add.class, Default.class);
System.out.println(list);
}
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class Grade {
//班级号
@NotBlank
private String no;
}
@NotNull
@Valid //被引用对象加@Valid注解才可以完成级联校验
private Grade grade;
}
userInfo.setGrade(new Grade());
List<String> list = ValidationUtil.valid(userInfo, UserInfo.Add.class, Default.class);
注解
package com.zs.validation.annotation;
import jakarta.validation.Constraint;
import jakarta.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.RetentionPolicy.RUNTIME;
@Documented
@Constraint(validatedBy = {UserStatusValidator.class })//指定当前注解要被谁来完成校验工作
@Target({FIELD})
@Retention(RUNTIME)
public @interface UserStatus {
String message() default "{userStatus必须是范围内的值}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
注解校验器
public class UserStatusValidator implements ConstraintValidator<UserStatus, String> {
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
if (s == null) {
return true;
} else {
Set<String> set = new HashSet<>();
set.add("10");
set.add("20");
set.add("30");
return set.contains(s);
}
}
@Override
public void initialize(UserStatus constraintAnnotation) {
}
}
使用
@UserStatus
private String status;
测试
@Test
public void test01(){
UserInfo userInfo = new UserInfo();
userInfo.setAge(19);
userInfo.setName("zs");
userInfo.setEmail("aaaa@qq.com");
userInfo.setPhone("13516466501");
userInfo.setBirthday(LocalDateTime.now().minusDays(1));
userInfo.setPersonalPage("http://www.baidu.com");
userInfo.setGrade(new Grade().setNo("11"));
userInfo.setStatus("10");
List<String> list = ValidationUtil.valid(userInfo, UserInfo.Add.class, Default.class);
System.out.println(list);
}
package com.zs.validation;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import org.hibernate.validator.HibernateValidator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class ValidationUtil {
//线程安全的 http://www.360doc.com/content/16/0222/17/16926569_536478632.shtml
private static Validator validator;
private static Validator failFastValidator;
static {
//默认校验器
validator = Validation.buildDefaultValidatorFactory().getValidator();
//快速失败的校验器
failFastValidator = Validation.byProvider(HibernateValidator.class)
.configure().failFast(true) //配置快速失败
.buildValidatorFactory().getValidator();
}
public static List<String> valid(Object obj,Class<?>... groups) {
//如果被校验对象 没有校验通过,则set里面就有校验信息
Set<ConstraintViolation<Object>> set = validator.validate(obj,groups);
List<String> list = set.stream().map(v ->
"属性:" + v.getPropertyPath() +
",属性的值" + v.getInvalidValue() +
",校验不通过的提示信息:" + v.getMessage() +
",消息模板(为被替换的提示信息):" + v.getMessageTemplate()
)
.collect(Collectors.toList());
return list;
}
public static List<String> validFailFast(Object obj,Class<?>... groups) {
//如果被校验对象 没有校验通过,则set里面就有校验信息
Set<ConstraintViolation<Object>> set = failFastValidator.validate(obj,groups);
List<String> list = set.stream().map(v ->
"属性:" + v.getPropertyPath() +
",属性的值" + v.getInvalidValue() +
",校验不通过的提示信息:" + v.getMessage() +
",消息模板(为被替换的提示信息):" + v.getMessageTemplate()
)
.collect(Collectors.toList());
return list;
}
}
package com.zs.validation;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.executable.ExecutableValidator;
import org.hibernate.validator.HibernateValidator;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class ValidationUtil {
//线程安全的 http://www.360doc.com/content/16/0222/17/16926569_536478632.shtml
private static Validator validator;
private static Validator failFastValidator;
private static ExecutableValidator executableValidator;
static {
//默认校验器
validator = Validation.buildDefaultValidatorFactory().getValidator();
//快速失败的校验器
failFastValidator = Validation.byProvider(HibernateValidator.class)
.configure().failFast(true) //配置快速失败
.buildValidatorFactory().getValidator();
//校验入参或返回值
executableValidator = validator.forExecutables();
}
public static List<String> valid(Object obj,Class<?>... groups) {
//如果被校验对象 没有校验通过,则set里面就有校验信息
Set<ConstraintViolation<Object>> set = validator.validate(obj,groups);
List<String> list = set.stream().map(v ->
"属性:" + v.getPropertyPath() +
",属性的值" + v.getInvalidValue() +
",校验不通过的提示信息:" + v.getMessage() +
",消息模板(为被替换的提示信息):" + v.getMessageTemplate()
)
.collect(Collectors.toList());
return list;
}
public static List<String> validFailFast(Object obj,Class<?>... groups) {
//如果被校验对象 没有校验通过,则set里面就有校验信息
Set<ConstraintViolation<Object>> set = failFastValidator.validate(obj,groups);
List<String> list = set.stream().map(v ->
"属性:" + v.getPropertyPath() +
",属性的值" + v.getInvalidValue() +
",校验不通过的提示信息:" + v.getMessage() +
",消息模板(为被替换的提示信息):" + v.getMessageTemplate()
)
.collect(Collectors.toList());
return list;
}
/**
* 非bean参数校验
*
* @param object 对象
* @param method 方法
* @param parameterValues 参数值
* @param groups 组
* @return {@link List}<{@link String}>
*/
public static <T> List<String> validNotBean(T object, Method method, Object[] parameterValues, Class<?>... groups) {
Set<ConstraintViolation<Object>> set = executableValidator.validateParameters(object,method,parameterValues,groups);
List<String> list = set.stream().map(v ->
"属性:" + v.getPropertyPath() +
",属性的值" + v.getInvalidValue() +
",校验不通过的提示信息:" + v.getMessage() +
",消息模板(为被替换的提示信息):" + v.getMessageTemplate()
)
.collect(Collectors.toList());
return list;
}
}
/**
* 方法非bean类型的入参校验
* 1. 方法参数前加注释
* 2. 执行入参校验,真正要用的话可以使用AOP编程来使用,web环境是spring已经做了
*
* @param name 名字
* @return {@link String}
*/
public String getByName(@NotNull String name) {
StackTraceElement st = Thread.currentThread().getStackTrace()[1];
String methodName = st.getMethodName();
Method method = null;
try {
method = this.getClass().getDeclaredMethod(methodName,String.class);
} catch (Exception e) {
e.printStackTrace();
}
List<String> strings = ValidationUtil.validNotBean(this, method, new Object[]{name});
System.out.println(strings);
return "ok";
}
@Test
public void test02(){
UserInfoService userInfoService = new UserInfoService();
String byName = userInfoService.getByName(null);
System.out.println(byName);
}
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.5.0version>
<scope>importscope>
<type>pomtype>
dependency>
dependencies>
dependencyManagement>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-validationartifactId>
dependency>
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserInfoHandler {
@GetMapping("/getByName")
public String getByName(String name){
return name + "ok";
}
}
package com.zs;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class);
}
}
/**
* 编程式校验
*
* @param userInfo 用户信息
* @return {@link String}
*/
@GetMapping("/addUser")
public String addUser(UserInfo userInfo){
List<String> result = ValidationUtil.valid(userInfo);
if (result.size() > 0) {
return "failed";
} else {
return "success";
}
}
@GetMapping("/addUser2")
public String addUser2(@Valid UserInfo userInfo, BindingResult bindingResult){
if (bindingResult.hasErrors()) { //判断是不是满足约束
List<ObjectError> allErrors = bindingResult.getAllErrors();
for (ObjectError error : allErrors) {
System.out.println(error.getObjectName() + "::" + error.getDefaultMessage());
}
//获取没通过校验的字段详情
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
System.out.println(fieldError.getField() + ":" + fieldError.getDefaultMessage()
+ ",当前没通过校验规则的值是:" + fieldError.getRejectedValue());
}
}
return "ok";
}
userInfo::你的名字不能为空
userInfo::不能为null
userInfo::不能为空
userInfo::不能为null
name:你的名字不能为空,当前没通过校验规则的值是:null
birthday:不能为null,当前没通过校验规则的值是:null
email:不能为空,当前没通过校验规则的值是:null
grade:不能为null,当前没通过校验规则的值是:null
/**
* 编程式校验
*
* @param userInfo 用户信息
* @return {@link String}
*/
@GetMapping("/addUser3")
public String addUser3(@Validated(value={UserInfo.Add.class, Default.class}) UserInfo userInfo, BindingResult bindingResult){
if (bindingResult.hasErrors()) { //判断是不是满足约束
List<ObjectError> allErrors = bindingResult.getAllErrors();
for (ObjectError error : allErrors) {
System.out.println(error.getObjectName() + "::" + error.getDefaultMessage());
}
//获取没通过校验的字段详情
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
System.out.println(fieldError.getField() + ":" + fieldError.getDefaultMessage()
+ ",当前没通过校验规则的值是:" + fieldError.getRejectedValue());
}
}
return "ok";
}
@GetMapping("/addUser4")
public String addUser4(@Validated(value={UserInfo.Add.class, Default.class}) UserInfo userInfo){
return "ok";
}
@ExceptionHandler(BindException.class)
public String handleEx(BindException e) {
List<FieldError> fieldErrors = e.getFieldErrors();
StringBuilder stringBuilder = new StringBuilder();
for (FieldError fe : fieldErrors) {
stringBuilder.append("属性:").append(fe.getField())
.append("校验不通过,原因:").append(fe.getDefaultMessage())
.append(";");
}
return stringBuilder.toString();
}
@Validated 可以指定分组
@Validated 支持方法参数的自动校验
@RestController
@Validated //表示整个类都启用校验,如果碰到入参含有bean validation 注解的话,就会自动校验
public class UserInfoHandler {
@GetMapping("/getByName")
public String getByName(@NotNull String name){
return name + "ok";
}
//@Validated 注解写在方法上的时候报的错误
@ExceptionHandler(BindException.class)
@ResponseBody
public String handleEx(BindException e) {
List<FieldError> fieldErrors = e.getFieldErrors();
StringBuilder stringBuilder = new StringBuilder();
for (FieldError fe : fieldErrors) {
stringBuilder.append("属性:").append(fe.getField())
.append("校验不通过,原因:").append(fe.getDefaultMessage())
.append(";");
}
return stringBuilder.toString();
}
//@Validated 注解写在类上报的异常
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
public List<String> handleEx(ConstraintViolationException e) {
Set<ConstraintViolation<?>> set = e.getConstraintViolations();
List<String> list = set.stream().map(v ->
"属性:" + v.getPropertyPath() +
",属性的值" + v.getInvalidValue() +
",校验不通过的提示信息:" + v.getMessage() +
",消息模板(为被替换的提示信息):" + v.getMessageTemplate()
)
.collect(Collectors.toList());
return list;
}
在某些项目场景中,需要使用代码校验实体类的参数值是否符合需求,并且返回值是动态的情况下,此时需要校验工具类来实现此功能。
org.hibernate
hibernate-validator
6.0.16.Final
package com.asyf.demo.other_api.hibernatevalidator;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.HibernateValidator;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.groups.Default;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @Description 实体校验工具类
*/
@Slf4j
public class ValidateUtil {
/**
* 验证器
*/
private static Validator validator;
static {
// validator = Validation.buildDefaultValidatorFactory().getValidator();
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
// 快速失败模式
.failFast(false)
.buildValidatorFactory();
validator = validatorFactory.getValidator();
}
/**
* 校验实体,返回实体所有属性的校验结果
*
* @param obj
* @param
* @return
*/
public static <T> ValidationResult validateEntity(T obj) {
//解析校验结果
Set<ConstraintViolation<T>> validateSet = validator.validate(obj, Default.class);
return buildValidationResult(validateSet);
}
/**
* 校验指定实体的指定属性是否存在异常
*
* @param obj
* @param propertyName
* @param
* @return
*/
public static <T> ValidationResult validateProperty(T obj, String propertyName) {
Set<ConstraintViolation<T>> validateSet = validator.validateProperty(obj, propertyName, Default.class);
return buildValidationResult(validateSet);
}
/**
* 将异常结果封装返回
*
* @param validateSet
* @param
* @return
*/
private static <T> ValidationResult buildValidationResult(Set<ConstraintViolation<T>> validateSet) {
ValidationResult validationResult = new ValidationResult();
if (!validateSet.isEmpty()) {
validationResult.setHasErrors(true);
Map<String, String> errorMsgMap = new HashMap<>();
for (ConstraintViolation<T> constraintViolation : validateSet) {
errorMsgMap.put(constraintViolation.getPropertyPath().toString(), constraintViolation.getMessage());
}
validationResult.setErrorMsg(errorMsgMap);
}
return validationResult;
}
public static void main(String[] args) {
User user = new User();
ValidationResult validationResult = ValidateUtil.validateEntity(user);
log.info(JSONUtil.toJsonStr(validationResult));
//og.info(validationResult.getMessage());
}
}
package com.asyf.demo.other_api.hibernatevalidator;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.text.MessageFormat;
import java.util.Map;
@Data
public class ValidationResult {
/**
* 是否有异常
*/
private boolean hasErrors;
/**
* 异常消息记录
*/
private Map<String, String> errorMsg;
/**
* 获取异常消息组装
*
* @return
*/
public String getMessage() {
if (errorMsg == null || errorMsg.isEmpty()) {
return StringUtils.EMPTY;
}
StringBuilder message = new StringBuilder();
errorMsg.forEach((key, value) -> {
message.append(MessageFormat.format("{0}:{1} \r\n", key, value));
});
return message.toString();
}
}
package com.asyf.demo.other_api.hibernatevalidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MyConstraintValidator.class)
public @interface MyValidatorAnnotation {
String message() default "性别有误";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String type() default "abc";
}
package com.asyf.demo.other_api.hibernatevalidator;
import lombok.extern.slf4j.Slf4j;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
@Slf4j
public class MyConstraintValidator implements ConstraintValidator<MyValidatorAnnotation, String> {
private MyValidatorAnnotation annotation;
public MyConstraintValidator() {
//每添加一次注解会实例化一个对象
//log.info("构造函数");
}
@Override
public void initialize(MyValidatorAnnotation annotation) {
//log.info("初始化");
this.annotation = annotation;
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
log.info("校验 type:{}", annotation.type());
//禁用默认的message的值
context.disableDefaultConstraintViolation();
//重新添加错误提示语句
context.buildConstraintViolationWithTemplate("重新添加错误提示语句").addConstraintViolation();
//返回校验结果
return "正确的值".equals(value);
}
}
package com.asyf.demo.other_api.hibernatevalidator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
public class User {
// @NotBlank
@MyValidatorAnnotation(type = "1", message = "name错误")
private String name;
@NotNull
@JsonIgnore
private Integer age;
@MyValidatorAnnotation(type = "2", message = "email错误")
private String email;
}
public static void main(String[] args) {
User user = new User();
ValidationResult validationResult = ValidateUtil.validateEntity(user);
log.info(JSONUtil.toJsonStr(validationResult));
//og.info(validationResult.getMessage());
}
INFO [main] - 校验 type:2
INFO [main] - 校验 type:1
INFO [main] - {"hasErrors":true,"errorMsg":{"name":"重新添加错误提示语句","email":"重新添
https://www.bilibili.com/video/BV1UE411t7BZ?spm_id_from=333.337.search-card.all.click&vd_source=746baba3d7924e4ac64a8318afa1567f