如何使用Bean Validation 解决业务中参数校验

网友投稿 973 2022-12-24

如何使用Bean Validation 解决业务中参数校验

如何使用Bean Validation 解决业务中参数校验

前言

在开发中经常需要写一些字段校验的代码,比如字段非空,字段长度限制,邮箱格式验证等等,写这些与业务逻辑关系不大的代码个人感觉有点麻烦:

验证代码繁琐,重复劳动

方法内代码显得冗长

每次要看哪些参数验证是否完整,需要去翻阅验证逻辑代码

叙述

Bean Validation是一个通过配置注解来验证参数的框架,它包含两部分Bean Validation API和Hibernate Validator。

Bean Validation API是java定义的一个验证参数的规范。

Hibernate Validator是Bean Validation API的一个实现。

@Valid和Validated的比较

Spring Validation验证框架对参数的验证机制提供了@Validated(Spring's jsR-303规范,是标准JSR-303的一个变种),javax提供了@Valid(标准JSR-303规范),配合BindingResult可以直接提供参数验证结果。

@Valid : 没有分组功能,可以用在方法、构造函数、方法参数和成员属性(field)上,如果一个待验证的pojo类,其中还包含了待验证的对象,需要在待验证对象上注解@valid,才能验证待验证对象中的成员属性

@Validated :提供分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制,用在类型、方法和方法参数上。但不能用于成员属性(field)。

两者都可以用在方法入参上,但都无法单独提供嵌套验证功能,都能配合嵌套验证注解@Valid进行嵌套验证。

嵌套验证示例:

public class ClassRoom{

@NotNull

String name;

@Valid // 嵌套校验,校验参数内部的属性

@NotNull

Student student;

}

@GetMapping("/room") // 此处可使用 @Valid 或 @Validated, 将会进行嵌套校验

public String validator(@Validated ClassRoom classRoom, BindingResult result) {

if (result.hasErrors()) {

return result.getFieldError().getDefaultMessage();

}

return "ok";

}

BindingResult 的使用

BindingResult必须跟在被校验参数之后,若被校验参数之后没有BindingResult对象,将会抛出BindException。

@GetMapping("/room")

public String validator(@Validated ClassRoom classRoom, BindingResult result) {

if (result.hasErrors()) {

return result.getFieldError().getDefaultMessage();

}

return "ok";

}

不要使用 BindingResult 接收String等简单对象的错误信息。简单对象校验失败,会抛出 ConstraintViolationException。主要就是接不着,你要写也算是没关系…

// ❌ 错误用法,也没有特别的错,只是 result 是接不到值。

@GetMapping("/room")

@Validated // 启用校验

public String validator(@NotNull String name, BindingResult result) {

if (result.hasErrors()) {

return result.getFieldError().getDefaultMessage();

}

return "ok";

}

修改校验失败的提示信息

可以通过各个校验注解的message属性设置更友好的提示信息。

public class ClassRoom{

@NotNull(message = "Classroom name must not be null")

String name;

@Valid

@NotNull

Student student;

}

@GetMapping("/room")

@Validated

public String validator(ClassRoom classRoom, BindingResult result, @NotNull(message = "姓名不能为空") String name) {

if (result.hasErrors()) {

return result.getFieldError().getDefaultMessage();

}

return "ok";

}

message属性配置国际化的消息也可以的,message中填写国际化消息的code,在抛出异常时根据code处理一下就好了。

@GetMapping("/room")

@Validated

public String validator(@NotNull(message = "demo.message.notnull") String name) {

if (result.hasErrors()) {

return result.getFieldError().getDefaultMessage();

}

return "ok";

}

// message_zh_CN.properties

demo.message.notnull=xxx消息不能为空

// message_en_US.properties

demo.message.notnull=xxx message must no be null

hibernate-validator 的使用

1.引入pom

org.hibernate

hibernate-validator

5.3.1.Final

2.dto入参对象属性加入注解

@Data

public class UserModel implements Serializable {

private String id;

@NotBlank(message = "用户名不能为空")

private String name;

@NotNull(message = "性别不能不填")

private Byte gender;

@NotNull(message = "年龄不能不填")

@Min(value = 0,message = "年龄必须大于0岁")

@Max(value = 150,message = "年龄必须小于150岁")

private Integer age;

@NotBlank(message = "手机号不能不填")

private String telphone;

private String registerMode;

private String thirdPartyId;

private String encrptPassward;

}

方法一:3.controller方法入参加入校验(@Validated )

@GetMapping("/getUser")

public String validator(@Validated UserModel userModel , BindingResult result) {

if (result.hasErrors()) {

return result.getFieldError().getDefaultMessage();

}

return "ok";

}

方法二:3.自定义封装ValidatorImpl类

@Component

public class ValidatorImpl implements InitializingBean{

private Validator validator;

//实现校验方法并返回校验结果

public ValidationResult validate(Object bean){

final ValidationResult result=new ValidationResult();

Set> validate = validator.validate(bean);

if (validate.size()>0) {

result.setHasError(true);

validate.forEach(constraintViolation->{

String errMsg=constraintViolation.getMessage();

String propertyName=constraintViolation.getPropertyPath().toString();

result.getErrorMsgMap().put(propertyName,errMsg);

});

}

return result;

}

@Override

public void afterPropertiesSet() throws Exception {

this.validator= Validation.buildDefaultValidatorFactory().getValidator();

}

}

方法二:4.自定义封装ValidationResult 类

public class ValidationResult {

public boolean hasError=false;

private Map&ltkEHORHUbHT;String,String> errorMsgMap=new HashMap<>();

//实现通用的通过格式化字符串信息获取错误结果的msg方法

public String getErrMsg(){

return StringUtils.join(errorMsgMap.values().toArray(),",");

}

public boolean isHasError() {

return hasError;

}

public void setHasError(boolean hasError) {

this.hasError = hasError;

}

public Map getErrorMsgMap() {

return errorMsgMap;

}

public void setErrorMsgMap(Map errorMsgMap) {

this.errorMsgMap = errorMsgMap;

}

}

5.controller方法入参加入校验

@Autowired

private ValidatorImpl validator;

@Override

@Transactional(rollbackFor = Exception.class)

public void register(UserModel userModel) throws BusinessException {

UserDo userDo=new UserDo();

if (userModel == null) {

throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);

}

//validate进行入参校验

ValidationResult validate = validator.validate(userModel);

if (validate.isHasError()){

throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,validate.getErrMsg());

}

}

Bean Validation 的约束

@Null 被注释的元素必须为 null

@NotNull 被注释的元素必须不为 null

@AssertTrue 被注释的元素必须为 true

@AssertFalse 被注释的元素必须为 false

@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值

@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值

@DecimalMin(value) 被注释的元素必须是一个数http://字,其值必须大于等于指定的最小值

@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值

@Size(max, min) 被注释的元素的大小必须在指定的范围内

@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内

@Past 被注释的元素必须是一个过去的日期

@Future 被注释的元素必须是一个将来的日期

@Pattern(value) 被注释的元素必须符合指定的正则表达式

Hibernate Validator 附加的约束

Hibernate Validator 附加的 constraint:

@Email 被注释的元素必须是电子邮箱地址

@Length 被注释的字符串的大小必须在指定的范围内

@NotEmpty 被注释的字符串的必须非空

@Range 被注释的元素必须在合适的范围内

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:智能车载终端系统英文(智能车辆的英文)
下一篇:智能车载终端系统现状(智能车载终端系统现状研究)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~