hibernate validation,自定义validation注解:解决动态多字段联动校验问题
hibernate validation,自定义validation注解:解决动态多字段联动校验问题详细介绍
本文目录一览: spring validation 和 hibernate validation 哪个好
开源是3个框架共有的优点
Struts2框架(MVC框架)的优点如下:
1) 实现了MVC模式,层次结构清晰,使程序员只需关注业务逻辑的实现;
2) 丰富的标签库,大大提高了开发的效率;
3) Struts2提供丰富的拦截器实现
3) 通过配置文件,就可以掌握整个系统各个部分之间的关系;
4) 异常处理机制,只需在配置文件中配置异常的映射,即可对异常做相应的处理;
Spring框架的优点如下:
1) 无入侵性(在业务逻辑代码中感觉不到Spring框架的存在);
2) 各个组件之间的耦合极为松散;
3) 无需程序员自己实现singleton模式;
4) 通过AOP,可以实现事务管理和日志管理;
5) 整合其他的框架,如:struts框架和hibernate框架;
Hibernate框架(ORM框架)的优点如下:
1) 对象/关系数据库映射(ORM), 使用时只需操纵对象,使开发更加面向对象化;
2) 无入侵性;
3) 简洁的HQL语句,减少了JDBC与SQL操作数据库的代码量;
4) 移植性好;
缺点如下:
1) 对批量更新,删除的支持不好;
如何使用java validation api进行参数校验
JAVA中通过Hibernate-Validation进行参数验证
在开发JAVA服务器端代码时,我们会遇到对外部传来的参数合法性进行验证,而hibernate-validator提供了一些常用的参数校验注解,我们可以拿来使用。
1.maven中引入hibernate-validator对应的jar:
org.hibernate
hibernate-validator
4.3.1.Final
2.在Model中定义要校验的字段(即该字段不能为空,并且最大长度为14):
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
public class PayRequestDto {
/**
* 支付完成时间
**/
@NotEmpty(message="支付完成时间不能空")
@Size(max=14,message="支付完成时间长度不能超过{max}位")
private String payTime;
public String getPayTime() {
return payTime;
}
public void setPayTime(String payTime) {
this.payTime = payTime;
}
}
3.定义Validation工具类:
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import org.hibernate.validator.HibernateValidator;
import com.atai.framework.lang.AppException;
public class ValidationUtils {
/**
* 使用hibernate的注解来进行验证
*
*/
private static Validator validator = Validation
.byProvider(HibernateValidator.class).configure().failFast(true).buildValidatorFactory().getValidator();
/**
* 功能描述:
* 〈注解验证参数〉
*
* @param obj
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public static
void validate(T obj) {
Set
<constraintviolation
> constraintViolations = validator.validate(obj);
// 抛出检验异常
if (constraintViolations.size() > 0) {
throw new AppException("0001", String.format("参数校验失败:%s", constraintViolations.iterator().next().getMessage()));
}
}
}
4.在代码中调用工具类进行参数校验:
ValidationUtils.validate(requestDto);
以下是对hibernate-validator中部分注解进行描述:
@AssertTrue 用于boolean字段,该字段只能为true
@AssertFalse 该字段的值只能为false
@CreditCardNumber 对信用卡号进行一个大致的验证
@DecimalMax 只能小于或等于该值
@DecimalMin 只能大于或等于该值
@Digits(integer=,fraction=) 检查是否是一种数字的整数、分数,小数位数的数字
@Email 检查是否是一个有效的email地址
@Future 检查该字段的日期是否是属于将来的日期
@Length(min=,max=) 检查所属的字段的长度是否在min和max之间,只能用于字符串
@Max 该字段的值只能小于或等于该值
@Min 该字段的值只能大于或等于该值
@NotNull 不能为null
@NotBlank 不能为空,检查时会将空格忽略
@NotEmpty 不能为空,这里的空是指空字符串
@Null 检查该字段为空
@Past 检查该字段的日期是在过去
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内
@Size(min=, max=) 检查该字段的size是否在min和max之间,可以是字符串、数组、集合、Map等
@URL(protocol=,host,port) 检查是否是一个有效的URL,如果提供了protocol,host等,则该URL还需满足提供的条件
@Valid 该注解主要用于字段为一个包含其他对象的集合或map或数组的字段,或该字段直接为一个其他对象的引用,这样在检查当前对象的同时也会检查该字段所引用的对象
</constraintviolation
hibernate validator.validateproperty一次可以验证多个属性吗
可以。flex可以写自定义验证,根据自己的需要写验证。 下面发个例子: package myCompenent { import mx.validators.Validator; //引用Validator类 import mx.validators.ValidationResult; //引用ValidationResult类 public class myValidators...
SpringBoot 参数校验,高级特性,非常实用
之前也写过一篇关于 Spring Validation 使用的文章,不过自我感觉还是浮于表面,本次打算彻底搞懂 Spring Validation 。
本文会详细介绍 Spring Validation 各种场景下的最佳实践及其实现原理,死磕到底!
Java API 规范 ( JSR303 ) 定义了 Bean 校验的标准 validation-api ,但没有提供实现。 hibernate validation 是对这个规范的实现,并增加了校验注解如 @Email 、 @Length 等。 Spring Validation 是对 hibernate validation 的二次封装,用于支持 spring mvc 参数自动校验。接下来,我们以 spring-boot 项目为例,介绍 Spring Validation 的使用。
如果 spring-boot 版本小于 2.3.x , spring-boot-starter-web 会自动传入 hibernate-validator 依赖。如果 spring-boot 版本大于 2.3.x ,则需要手动引入依赖:
对于 web 服务来说,为防止非法参数对业务造成影响,在 Controller 层一定要做参数校验的!大部分情况下,请求参数分为如下两种形式:
下面我们简单介绍下 requestBody 和 requestParam/PathVariable 的参数校验实战!
POST 、 PUT 请求一般会使用 requestBody 传递参数,这种情况下,后端使用** DTO 对象 进行接收。 只要给 DTO 对象加上 @Validated 注解就能实现自动参数校验**。比如,有一个保存 User 的接口,要求 userName 长度是 2-10 , account 和 password 字段长度是 6-20 。如果校验失败,会抛出 MethodArgumentNotValidException 异常, Spring 默认会将其转为 400(Bad Request) 请求。
DTO 表示数据传输对象(Data Transfer Object),用于服务器和客户端之间交互传输使用的 。在 spring-web 项目中可以表示用于接收请求参数的 Bean 对象。
这种情况下, 使用 @Valid 和 @Validated 都可以 。
前面说过,如果校验失败,会抛出 MethodArgumentNotValidException 或者 ConstraintViolationException 异常。在实际项目开发中,通常会用 统一异常处理 来返回一个更友好的提示。比如我们系统要求无论发送什么异常, http 的状态码必须返回 200 ,由业务码去区分系统的异常情况。
在实际项目中,可能多个方法需要使用同一个 DTO 类来接收参数,而不同方法的校验规则很可能是不一样的。这个时候,简单地在 DTO 类的字段上加约束注解无法解决这个问题。因此, spring-validation 支持了 分组校验 的功能,专门用来解决这类问题。还是上面的例子,比如保存 User 的时候, UserId 是可空的,但是更新 User 的时候, UserId 的值必须 >=10000000000000000L ;其它字段的校验规则在两种情况下一样。这个时候使用 分组校验 的代码示例如下:
前面的示例中, DTO 类里面的字段都是 基本数据类型 和 String 类型。但是实际场景中,有可能某个字段也是一个对象,这种情况先,可以使用 嵌套校验 。
比如,上面保存 User 信息的时候同时还带有 Job 信息。需要注意的是, 此时 DTO 类的对应字段必须标记 @Valid 注解 。
嵌套校验可以结合分组校验一起使用。还有就是 嵌套集合校验 会对集合里面的每一项都进行校验,例如 List 字段会对这个 list 里面的每一个 Job 对象都进行校验。
如果请求体直接传递了 json 数组给后台,并希望对数组中的每一项都进行参数校验。此时,如果我们直接使用 java.util.Collection 下的 list 或者 set 来接收数据,参数校验并不会生效!我们可以使用自定义 list 集合来接收参数:
@Delegate 注解受 lombok 版本限制, 1.18.6 以上版本可支持。如果校验不通过,会抛出 NotReadablePropertyException ,同样可以使用统一异常进行处理。
比如,我们需要一次性保存多个 User 对象, Controller 层的方法可以这么写:
业务需求总是比框架提供的这些简单校验要复杂的多,我们可以自定义校验来满足我们的需求。自定义 spring validation 非常简单,假设我们自定义 加密id (由数字或者 a-f 的字母组成, 32-256 长度)校验,主要分为两步:
这样我们就可以使用 @EncryptId 进行参数校验了!
上面的示例都是基于 注解 来实现自动校验的,在某些情况下,我们可能希望以 编程方式 调用验证。这个时候可以注入 javax.validation.Validator 对象,然后再调用其 api 。
Spring Validation 默认会校验完所有字段,然后才抛出异常。可以通过一些简单的配置,开启 Fali Fast 模式,一旦校验失败就立即返回。
在 spring-mvc 中, RequestResponseBodyMethodProcessor 是用于解析 @RequestBody 标注的参数以及处理 @ResponseBody 标注方法的返回值的。显然,执行参数校验的逻辑肯定就在解析参数的方法 resolveArgument() 中:
可以看到, resolveArgument() 调用了 validateIfApplicable() 进行参数校验。
看到这里,大家应该能明白为什么这种场景下 @Validated 、 @Valid 两个注解可以混用。我们接下来继续看 WebDataBinder.validate() 实现。
最终发现底层最终还是调用了 Hibernate Validator 进行真正的校验处理。
接着看一下 MethodValidationInterceptor :
实际上,不管是 requestBody参数校验 还是 方法级别的校验 ,最终都是调用 Hibernate Validator 执行校验, Spring Validation 只是做了一层封装 。
本人花费2个月时间,整理了一套JAVA开发技术资料,内容涵盖java基础,分布式、微服务等主流技术资料,包含大厂面经,学习笔记、源码讲义、项目实战、讲解视频。
java面试资料
私信回复【2022面试资料】
领取更多学习资料
hibernate在配置文件中声明的表如果数据库中没有这张表会自动新建一个吗?
会,但是只建表不建库。
当引入hibernate时,可以创建数据库表的配置文件。可以根据表的配置文件自动在数据库建表。(数据库要预先建立好,因为hibernate只会建表,不会建库)
在配置文件 hibernate.cfg.cml 中加入参数 ,配置相关数据源参数和pojo文件。
update 表示自动根据model对象来更新表结构,启动hibernate时会自动检查数据库,如果缺少表,则自动建表;如果表里缺少列,则自动添加列。
#create:启动hibernate时,自动删除原来的表,新建所有的表,所以每次启动后的以前数据都会丢失。
#create-drop:启动hibernate时,自动创建表,程序关闭时,自动把相应的表都删除。所以程序结束时,表和数据也不会再存在。
具体代码如下:
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/test
root
mysecretpassword
org.hibernate.dialect.MySQLDialect
update
none
true
JSR303数据校验
JSR303技术,JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint,在springboot中使用也比较简便。
在 javax.validation.constraints 包下有许多的注解:
常用的校验注解补充:
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格. @NotEmpty 检查约束元素是否为NULL或者是EMPTY. @Length 被检查的字符串长度是否在指定的范围内 @CreditCardNumber 信用卡验证 @Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。 @URL 验证是否是一个url地址
注意: 一个字段可以标注多个校验注解。
如果只标注了注解字段,不启用@valid的是不生效的。
对于程序可能有很多的校验注解,可能会出现多个校验错误,我们可以定义一个统一的异常处理类,帮我们捕捉校验错误并返回提示信息,这里可以利用Spring的ControllerAdvice技术。
对于校验可能会出现的异常,我们将其抛出,不予捕捉感知,都交给我们的统一异常处理类处理,返回提示信息。
对于不同的操作,字段校验的规则和数量可能是不同的,所以我们将校验规则分组,对于不同的操作进行不同的校验组,使用groups属性。
1.想要使用分组校验功能,根据文档我们首先编写不同的校验组接口,只编写空接口,用来表示就可以了:
2.编写好分组接口,对于不同的检验规则,标注不同的分组标识:
3.在controller方法上标注不同的分组校验,使用@Validated注解:
@Validated({AddGroup.class}) :启用不同的分组校验规则。
注意: 在使用分组校验的情况下,对于没有标注分组的校验规则,默认是不生效的,只有标注了分组的校验规则才会生效。
1.编写一个自定义的校验注解
导入依赖:
编写自定义校验注解
用来验证自定义的字段值,非0即1。
2.编写一个自定义的校验器
3.关联自定义的校验器和自定义的校验注解
在自定义的校验注解中添加自己的校验器,就关联好了,一个校验注解可以指定多个不同类型的校验器,适配不同类型的校验。关联完成就可以使用了。
4.使用
测试:
save方法传参: showStatus: 3 返回:
自定义校验注解生效。
SpringBoot Validation参数校验 详解自定义注解规则和分组校验
Hibernate Validator 是 Bean Validation 的参考实现 。Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint
在日常开发中,Hibernate Validator经常用来验证bean的字段,基于注解,方便快捷高效。
在SpringBoot中可以使用@Validated,注解Hibernate Validator加强版,也可以使用@Valid原来Bean Validation java版本
Bean Validation 中内置的 constraint
Hibernate Validator 附加的 constraint
message支持表达式和EL表达式 ,比如message = "姓名长度限制为{min}到{max} ${1+2}")
想把错误描述统一写到properties的话,在classpath下面新建
ValidationMessages_zh_CN.properties文件(注意value需要转换为unicode编码),然后用{}格式的占位符
hibernate补充的注解中,最后3个不常用,可忽略。
主要区分下@NotNull @NotEmpty @NotBlank 3个注解的区别:
如果同一个参数,需要在不同场景下应用不同的校验规则,就需要用到分组校验了。比如:新注册用户还没起名字,我们允许name字段为空,但是在更新时候不允许将名字更新为空字符。
分组校验有三个步骤:
自定义的Update分组接口继承了Default接口。校验注解(如: @NotBlank)和@validated默认其他注解都属于Default.class分组,这一点在
javax.validation.groups.Default注释中有说明
在编写Update分组接口时,如果继承了Default,下面两个写法就是等效的:
@Validated({Update.class}),@Validated({Update.class,Default.class})
如果Update不继承Default,@Validated({Update.class})就只会校验属于Update.class分组的参数字段
如果 UserVO 类中增加一个 OrderVO 类的属性,而 OrderVO 中的属性也需要校验,就用到递归校验了,只要在相应属性上增加@Valid注解即可实现(对于集合同样适用)
validation 为我们提供了这么多特性,几乎可以满足日常开发中绝大多数参数校验场景了。但是,一个好的框架一定是方便扩展的。有了扩展能力,就能应对更多复杂的业务场景,毕竟在开发过程中,唯一不变的就是变化本身。 Validation允许用户自定义校验
实现很简单,分两步:
注意:message用于显示错误信息这个字段是必须的,groups和payload也是必须的
@Constraint(validatedBy = {
HandsomeBoyValidator.class})用来指定处理这个注解逻辑的类
注意这里验证逻辑我抽出来单独写了一个工具类,ValidatorUtil
我自定义了补充了很多验证器,包括日期验证,枚举验证,手机号验证,金额验证
自定义校验注解使用起来和内置注解无异,在需要的字段上添加相应注解即可
使用 Validation API 进行参数效验步骤整个过程如下图所示,用户访问接口,然后进行参数效验 ,如果效验通过,则进入业务逻辑,否则抛出异常,交由全局异常处理器进行处理
全局异常出来请参考我这篇文章SpringBoot优雅的全局异常处理
自定义validation注解:解决动态多字段联动校验问题
javax.validation是基于JSR-303标准定义的一组接口,目的是使开发者简洁地校验参数,hibernate-validator实现了这一组接口,可以作为工具独立引用。
如果是SpringBoot项目则无需显示引用上述依赖,因为SpringBoot已经将上述依赖进行了集成。
现在我们假设一种场景订单新增了type1、type2两个字段,这两个字段影响对于orderId值范围判断,也就是说orderId范围判断不再是静态的,而是受其它字段影响。
针对这种情况第一步我们可以构造type1、type2、orderId组合字段,第二步自定义校验器将组合字段拆开进行业务校验。
本文第一章节介绍了validation基本概念,第二章节介绍了validation基本应用,第三章节介绍了通过自定义注解动态校验字段,希望本文对大家有所帮助。
javax 是如何实现依赖
参数校验是我们程序开发中必不可少的过程。用户在前端页面上填写表单时,前端js程序会校验参数的合法性,当数据到了后端,为了防止恶意操作,保持程序的健壮性,后端同样需要对数据进行校验。后端参数校验最简单的做法是直接在业务方法里面进行判断,当判断成功之后再继续往下执行。但这样带给我们的是代码的耦合,冗余。当我们多个地方需要校验时,我们就需要在每一个地方调用校验程序,导致代码很冗余,且不美观。
那么如何优雅的对参数进行校验呢?JSR303就是为了解决这个问题出现的,本篇文章主要是介绍 JSR303,Hibernate Validator 等校验工具的使用,以及自定义校验注解的使用。
校验框架介绍
JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean的属性上面,就可以在需要校验的时候进行校验了。注解如下:
Hibernate validator 在JSR303的基础上对校验注解进行了扩展,扩展注解如下:
Spring validtor 同样扩展了jsr303,并实现了方法参数和返回值的校验
Spring 提供了MethodValidationPostProcessor类,用于对方法的校验
代码实现
添加JAR包依赖
在pom.xml中添加如下依赖:
javax.validation
validation-api
1.1.0.Final
org.hibernate
hibernate-validator
5.2.0.Final
最简单的参数校验
1、Model 中添加校验注解
public class Book { private long id; /** * 书名 */ @NotEmpty(message = "书名不能为空") private String bookName; /** * ISBN号 */ @NotNull(message = "ISBN号不能为空") private String bookIsbn; /** * 单价 */ @DecimalMin(value = "0.1",message = "单价最低为0.1")private double price; // getter setter ....... }
2、在controller中使用此校验
/*** 添加Book对象* @param book */@RequestMapping(value = "/book", method = RequestMethod.POST) public void addBook(@RequestBody @Valid Book book) {System.out.println(book.toString());}
当访问这个post接口时,如果参数不符合Model中定义的话,程序中就回抛出400异常,并提示错误信息。
自定义校验注解
虽然jSR303和Hibernate Validtor 已经提供了很多校验注解,但是当面对复杂参数校验时,还是不能满足我们的要求,这时候我们就需要 自定义校验注解。
下面以“List数组中不能含有null元素”为实例自定义校验注解
1、注解定义如下:
package com.beiyan.validate.annotation;import javax.validation.Constraint;import javax.validation.Payload;import java.lang.annotation.*;import static java.lang.annotation.ElementType.*;import static java.lang.annotation.ElementType.PARAMETER;import static java.lang.annotation.RetentionPolicy.RUNTIME;/*** 自定义参数校验注解* 校验 List 集合中是否有null 元素 */@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)@Documented@Constraint(validatedBy = ListNotHasNullValidatorImpl.class)////此处指定了注解的实现类为ListNotHasNullValidatorImplpublic @interface ListNotHasNull { /*** 添加value属性,可以作为校验时的条件,若不需要,可去掉此处定义 */int value() default 0;String message() default "List集合中不能含有null元素";Class
[] groups() default {};Class
[] payload() default {}; /*** 定义List,为了让Bean的一个属性上可以添加多套规则 */@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})@Retention(RUNTIME)@Documented@interface List {ListNotHasNull[] value();}}
2、注解实现类:
package com.beiyan.validate.annotation;import org.springframework.stereotype.Service;import javax.validation.ConstraintValidator;import javax.validation.ConstraintValidatorContext;import java.util.List;/*** 自定义注解ListNotHasNull 的实现类* 用于判断List集合中是否含有null元素 */@Servicepublic class ListNotHasNullValidatorImpl implements ConstraintValidator
{ private int value;@Override public void initialize(ListNotHasNull constraintAnnotation) { //传入value 值,可以在校验中使用this.value = constraintAnnotation.value();} public boolean isValid(List list, ConstraintValidatorContext constraintValidatorContext) { for (Object object : list) { if (object == null) { //如果List集合中含有Null元素,校验失败return false;}} return true;}}
3、model添加注解:
public class User {//其他参数 ......./** * 所拥有的书籍列表 */ @NotEmpty(message = "所拥有书籍不能为空") @ListNotHasNull(message = "List 中不能含有null元素") @Valid private List
books; //getter setter 方法.......}
使用方法同上,在在需要校验的Model上面加上@Valid 即可
分组验证
对同一个Model,我们在增加和修改时对参数的校验也是不一样的,这个时候我们就需要定义分组验证,步骤如下
1、定义两个空接口,分别代表Person对象的增加校验规则和修改校验规则
/*** 可以在一个Model上面添加多套参数验证规则,此接口定义添加Person模型新增时的参数校验规则 */public interface PersonAddView {}/*** 可以在一个Model上面添加多套参数验证规则,此接口定义添加Person模型修改时的参数校验规则 */public interface PersonModifyView {}
2、Model上添加注解时使用指明所述的分组
public class Person { private long id; /*** 添加groups 属性,说明只在特定的验证规则里面起作用,不加则表示在使用Deafault规则时起作用 */@NotNull(groups = {PersonAddView.class, PersonModifyView.class}, message = "添加、修改用户时名字不能为空", payload = ValidateErrorLevel.Info.class)@ListNotHasNull.List({@ListNotHasNull(groups = {PersonAddView.class}, message = "添加上Name不能为空"),@ListNotHasNull(groups = {PersonModifyView.class}, message = "修改时Name不能为空")}) private String name;@NotNull(groups = {PersonAddView.class}, message = "添加用户时地址不能为空") private String address;@Min(value = 18, groups = {PersonAddView.class}, message = "姓名不能低于18岁")@Max(value = 30, groups = {PersonModifyView.class}, message = "姓名不能超过30岁") private int age; //getter setter 方法......}
3、启用校验
此时启用校验和之前的不同,需要指明启用哪一组规则
/*** 添加一个Person对象* 此处启用PersonAddView 这个验证规则* 备注:此处@Validated(PersonAddView.class) 表示使用PersonAndView这套校验规则,若使用@Valid 则表示使用默认校验规则,* 若两个规则同时加上去,则只有第一套起作用 */@RequestMapping(value = "/person", method = RequestMethod.POST) public void addPerson(@RequestBody @Validated({PersonAddView.class, Default.class}) Person person) {System.out.println(person.toString());} /*** 修改Person对象* 此处启用PersonModifyView 这个验证规则 */@RequestMapping(value = "/person", method = RequestMethod.PUT) public void modifyPerson(@RequestBody @Validated(value = {PersonModifyView.class}) Person person) {System.out.println(person.toString());}
Spring validator 方法级别的校验
JSR和Hibernate validator的校验只能对Object的属性进行校验,不能对单个的参数进行校验,spring 在此基础上进行了扩展,添加了MethodValidationPostProcessor拦截器,可以实现对方法参数的校验,实现如下:
1、实例化MethodValidationPostProcessor
@Bean public MethodValidationPostProcessor methodValidationPostProcessor() { return new MethodValidationPostProcessor();}
2、在所要实现方法参数校验的类上面添加@Validated,如下
@RestController@Validatedpublic class ValidateController {}
3、在方法上面添加校验规则:
@RequestMapping(value = "/test", method = RequestMethod.GET) public String paramCheck(@Length(min = 10) @RequestParam String name) {System.out.println(name); return null;}
当方法上面的参数校验失败,spring 框架就回抛出异常
{ "timestamp": 1380058, "status": 500, "error": "Internal Server Error", "exception": "javax.validation.ConstraintViolationException", "message": "No message available", "path": "/test"}
在pojo类中添加校验规则,哪个注解可以校验字符串的长度
1. 环境准备
springmvc中我们使用hibernate的校验框架validation(注:和hibernate没有任何关系),使用这个校验框架的话,需要导入jar包如下:
2. 配置校验器
在springmvc.xml配置文件中配置一下校验器,如下:
classpath:CustomValidationMessage
配置规则就是bean和property属性,别把class和文件名写错了就行,这里有个配置是资源文件名,这个文件中我们将会配置一些错误信息。配置好了校验器后,需要将校验器注入到处理器适配器中,还是在springmvc.xml文件中,将我们配好的validator注入进去,如下:
这样校验器就配置好了。
3. 在pojo中添加校验
注解
运行时检查
@AssertFalse 被注解的元素必须为false
@AssertTrue 被注解的元素必须为true
@DecimalMax(value) 被注解的元素必须为一个数字,其值必须小于等于指定的最小值
@DecimalMin(Value) 被注解的元素必须为一个数字,其值必须大于等于指定的最小值
@Digits(integer=, fraction=) 被注解的元素必须为一个数字,其值必须在可接受的范围内
@Future 被注解的元素必须是日期,检查给定的日期是否比现在晚
@Max(value) 被注解的元素必须为一个数字,其值必须小于等于指定的最大值(百度上好多传阅复制写错了 最小值)
@Min(value) 被注解的元素必须为一个数字,其值必须大于等于指定的最小值
@NotNull 被注解的元素必须不为null
@Null 被注解的元素必须为null
@Past(java.util.Date/Calendar) 被注解的元素必须过去的日期,检查标注对象中的值表示的日期比当前早
@Pattern(regex=, flag=) 被注解的元素必须符合正则表达式,检查该字符串是否能够在match指定的情况下被regex定义的正则表达式匹配
@Size(min=, max=) 被注解的元素必须在制定的范围(数据类型:String, Collection, Map and arrays)
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组, 那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验
@CreditCardNumber 对信用卡号进行一个大致的验证
@Email 被注释的元素必须是电子邮箱地址
@Length(min=, max=) 被注解的对象必须是字符串的大小必须在制定的范围内
@NotBlank 被注解的对象必须为字符串,不能为空,检查时会将空格忽略
@NotEmpty 被注释的对象必须为空(数据:String,Collection,Map,arrays)
@Range(min=, max=) 被注释的元素必须在合适的范围内 (数据:BigDecimal, BigInteger, String, byte, short, int, long and 原始类型的包装类 )
@URL(protocol=, host=, port=, regexp=, flags=) 被注解的对象必须是字符串,检查是否是一个有效的URL,如果提供了protocol,host等,则该URL还需满足提供的条件
hibernate校验框架提供了很多注解校验,我先简单罗列一下:
上面我简单罗列了一些校验的注解,不同的注解的具体使用方法可以参考官方文档或者网上资料,这里我选择两个注解来说明如何使用这个hibernate验证框架。首先在自己的pojo中需要验证的属性上添加相应的验证注解:
我们看到注解中可以指定message,那么这个message中的内容是错误消息配置文件中对应的key,取出来的就是对应的错误消息,所以针对这两个错误消息,我们写一下配置文件:
4. 捕获校验错误信息
上面已经将校验相关的配置都配好了,接下来就需要在controller的方法中捕获校验结果中的错误信息,然后将这些错误信息传到前台去显示。那么controller的方法中该如何去捕获呢?如下:
可以看出,在需要校验的pojo前边添加@Validated,在需要校验的pojo后边添加BindingResult bindingResult来接收校验出错信息。值得注意的是:@Validated和BindingResult bindingResult是配对出现,并且形参顺序是固定的(一前一后)。这样就可以顺利接收到错误信息了。关于前台的东西,我就不写了。
5. 分组校验
上面已经能完成springmvc的校验功能了,但是有个问题:刚刚是在pojo中定义了校验规则,但是pojo是被多个controller使用的,现在假如两个不同的controller使用的校验规则是不一样的,简单来说,一个controller不需要去校验生产日期,只要校验一下商品名称即可,另一个controller两个都要校验,这样就没法做了,因为两个controller都使用同一个pojo。
为了解决这个问题,我们可以定义多个校验分组(其实是一个Java接口),分组中定义有哪些规则,每个controller方法使用不同的校验分组即可。看一下下面的例子就明白了:
首先定义一个校验分组:
public interface ValidGroup1 {
//接口中不需要定义任何方法,仅仅是对不同的校验规则进行分组
//此分组只校验商品名称的长度
}
然后我们在刚刚的pojo中,添加这个分组,如下:
再看一下想要校验这个name字段的controller中是如何配置的:
这样该controller就不会去校验生产日期的字段了,通过这种方式可以解决不同的controller校验不同字段的问题。