Spring数据验证及Spring MVC拦截器
Spring数据验证及Spring MVC拦截器
应用程序在执行业务逻辑前,必须通过数据校验保证接收到的输入数据是正确合法的,如代表生日的日期应该是一个过去的时间、工资的数值必须是一个正数等。一般情况下,应用程序的开发是分层的,不同层的代码由不同的开发人员负责。很多时候,同样的数据验证会出现在不同的层中,这样就会导致代码冗余,为了避免这样的情况,最好将验证逻辑和相应的域模型进行绑定,将代码验证的逻辑集中起来管理。
JSR 303
JSR-303是 Java为 Bean 数据合法性校验所提供的标准框架,它已经包含在Java EE 6.0中。JSR-303通过在 Bean属性上标注类似于@NotNull、@Max 等标准的注解指定校验规则,并通过标准的验证接口对 Bean 进行验证。可以通过 http∶/jcp.org/en/jsr/detail?id=303 了解JSR-303的详细内容。 JSR-303定义了一套可标注在成员变量、属性方法上的校验注解,说明如表所示:
注解 | 说明 |
---|---|
@Null | 验证对象是否为null |
@NotNull | 验证对象是否不为null,无法检查长度为0的字符串,用于验证基本数据类型 |
@NotBlank | 检查约束字符串是不是null,被trim的长度是否大于0,值作用于字符串,并且会去除前后空格 |
@AssertTrue | 验证Boolean对象是否为true |
@AssertFalse | 验证Boolean对象是否为false |
@Max(value) | 验证Number和String对象是否小于等于指定的值 |
@Min(value) | 验证Number和String对象是否大于等于指定的值 |
@DecimalMax(value) | 被标注的值必须不大于约束中指定的最大值。这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示,小数存在精度 |
@DecimalMin(value) | 被标注的值必须不小于约束中指定的最小值。这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示,小数存在精度 |
@Digits(integer,fcaction) | 验证字符串是否是符合指定格式的数字,integer指定整数精度,fraction指定小数精度 |
@Size(min,max) | 验证对象(Array、Collection、Map、String)长度是否在给定的范围之内 |
@Past | 验证Date和Calender对象是否在当前时间之前 |
@Future | 验证Date和Calender对象是否在当前时间之后 |
@Pattern | 验证String对象是否符合正则表达式的规则 |
Hibernate Validator是JSR-303的一个参考实现,它除了支持所有标准的校验注解外,还支持如表所示的扩展注解。
@NotBlank | 检查约束字符串是不是Null,被Trim的长度是否大于0。只对字符串,且去掉前后空格 |
---|---|
@URL | 验证是否是合法的url |
验证是否是合法的邮件地址 | |
@CreditCardNumber | 验证是否是合法的信用卡号码 |
@Length(min,max) | 验证字符串的长度必须在指定的范围内 |
@NotEmpty | 检查元素是否为NULL或者EMPTY。用于Array、Collection、Map、String |
@Range(min,max,message) | 验证属性值必须在合适的范围内 |
JSR-303 的核心接口是 javax.validation.Validator,该接口根据目标对象类中所标注的校验注解进行数据校验,并得到校验结果。
SpringMVC数据验证
<mvc∶annotation-driven/>会默认装配一个LocalValidatorFactoryBean,通过在处理方法的入参上标注@Valid注解,即可让 Spring MVC 在完成数据绑定后执行数据校验工作。 在开发中凡是用户输入的数据都需要验证,例如登录时,用户填写的用户名或者密码;注册时,用户填写的注册信息等等,如果没有SpringMVC的数据验证,那么只能通过String类提供了API或者利用正则表达式进行验证。并且这是一件很繁琐的事情,下面将示例如果使用注解进制验证数据合法性。
使用注解
下面将以用户登录为例进行讲解,首先添加如下依赖:
1 | <!--hibernate-validator --> |
接下来新建VO类,使用注解
1 |
|
在上例的VO中,使用了@Max,@Min注解用于验证用户名长度必须在6-12位之间。验证密码时则使用了@Pattern注解,该注解可以以正则表达式来验证一个字符串是否符合标准,上例中的正则表达式表明字符串必须由6-12的数字、字母、下划线组成。
新建页面,用于填写用户名和密码:
1 | <body> |
接下来,新建Controller进行测试。
1 | package cn.bytecollege.controller; |
部署该应用,访问登录页面,在不填写任何内容的情况下提交表单,运行结果如下图:
在上例中可以看出在Controller的方法参数User上使用了@Valid注解,这个注解用于表明对该参数进行验证。而BindingResult对象则是用于获取验证的信息,SpringMVC会将校验结果保存在该对象。该对象主要有如下几个方法:
- FieldError getFieldError(String field)∶根据属性名获取对应的校验错误。
- List<FieldError> getFieldErrors()∶获取所有的属性校验错误。
- Object getFieldValue(String field)∶获取属性值。
- int getErrorCount()∶获取错误数量。
拦截器
当收到请求时,DispatcherServlet 将请求交给处理器映射(HandlerMapping),让它找出对应该请求的 HandlerExecutionChain 对象。在讲解 HandlerMapping 之前,有必要认识一下这个 HandlerExecutionChain 对象。 HandlerExecutionChain 顾名思义是一个执行链,它包含一个处理该请求的处理器(Handler),同时包括若干个对该请求实施拦截的拦截器(HandlerInterceptor)。当HandlerMapping 返回 HandlerExecutionChain 后,DispatcherServlet 将请求交给定义在HandlerExecutionChain 中的拦截器和处理器一并处理。 HandlerExecutionChain 是负责处理请求并返回 ModelAndView 的处理执行链,其结构如图所示。请求在被 Handler 执行的前后,链中装配的 HandlerInterceptor 会实施拦截操作。
拦截器方法
拦截器到底做了什么事情?我们通过考查拦截器的几个接口方法进行了解。
- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)∶在请求到达 Handler 之前,先执行这个前置处理方法。当该方法返回false 时,请求直接返回,不会传递到链中的下一个拦截器,更不会传递到处理器链末端的 Handler中。只有返回 true 时,请求才向链中的下一个处理节点传递。
- void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView)∶在请求被HandlerAdapter执行后,执行这个后置处理方法。
- void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex)∶在响应已经被渲染后,执行该方法。 位于处理器链末端的是一个 Handler,DispatcherServlet 通过 HandlerAdapter 适配器对 Handler 进行封装,并按统一的适配器接口对 Handler 处理方法进行调用。
拦截器使用
下面的示例将演示拦截器的使用:
首先,定义拦截器:
1 | package cn.bytecollege.interceptor; |
定义完拦截器后,需要在配置文件中进行如下配置,才能使拦截器生效:
1 | <!--配置拦截器--> |
运行结果如下图: