SpringMVC 框架

拦截器[Interceptor]

主要是针对SpringMVC框架中的控制器进行拦截

使用Interceptor的步骤

  1. ###### 编写一个 拦截器类,需要实现 HandlerInterceptor , 或者 继承 HandlerInterceptorAdapter

这个接口有三个方法

  • preHandle 方法, 在执行目标Handler【小C控制器中的某个方法】之前 被调用
  • postHandle 方法, 在执行目标Handler【小C控制器中的某个方法】之后,但是在View被渲染之前
  • afterCompletion 方法,也就是请求完成【VIEW被渲染】后执行

注:我们可以根据需要来决定重写哪个方法,不是所有方法都要重写的。

另外,preHandle 方法的返回值是布尔类型,为true时,则执行目标控制器中方法,如果为false,则应该直接响应客户端。

注:SpringMVC中提供了HandlerInterceptorAdapter类,我们只需要继承这个类即可,并重写你需要重写的方法即可。

  1. 在xxxx-servlet.xml中,来配置 拦截器。【注:SpringMVC中暂没有提供 拦截器的注解配置】
   <mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path=""/>
           <mvc:exclude-mapping path=""/>
           <bean class="注解的类路径"/>
       </mvc:interceptor>
       <!-- 可以配置多个 -->
   </mvc:interceptors>
  1. 如果我们配置了多个拦截器,则这些拦截器的执行顺序就是我们配置的顺序.

  2. 配置了多个拦截器后,此处假设我们有 Interceptor1, 和 Interceptor2, 它们的执行顺序:

    • Interceptor1.preHandle()
    • Interceptor2.preHandle()
    • 执行目标的Handler【也就是控制器的目标方法】
    • Interceptor2.postHandle()
    • Interceptor1.postHandle()
    • 渲染视图后
    • Interceptor2.afterCompletion()
    • Interceptor1.afterCompletion()

注:

​ 如果拦截器链中的某个拦截器的preHandle方法返回false, 则这个拦截器后面的拦截器以及目标Controller的方法都不再执行,当然,postHandle方法也不会执行,但是,preHandle方法返回true的那个拦截器中的afterCompletion方法会执行。

数据验证Bean Validation

前端页面我们可以通过JS来进行验证,但是,前端的验证是很容易被“跳过”的,所以,在后端我们还是需要做数据的验证,它是为了保证数据的合法性和可用性。

所以,在严谨的系统中,前后端的数据验证都是需要做的。

在SpringMVC框架中,后端如何来做数据的验证呢?

步骤

  1. WebMvcConfig类中,重写父类的 getValidator() 方法, 指定ValidationMessageSource,如果不指定,会去classpath下面查找一个名为 ValidationMessages的默认属性文件, 建议是我们自己指定

  2. 写一个方法,返回 ValidationSource, 具体参考代码

  3. 编写属性文件,可以以 国际化的格式来写,如:validationMessages_zh.properties, 它有三部份:

    • baseName, 如 ValidationMessages
    • 语言代码, 如: zh, en
    • 国家代码, 如: cn, us
  4. 利用 JSR-303的验证规范,导入 Hibernate-Validator 依赖【它是JSR303的实现者】

  5. 在你需要做数据验证的实体类[entity]或数据传输对象[dto]或 值对象[Value Object] 的上面添加如下的注解:

JSR303规范中定义的注解,所在包: javax.validation.constraints

| 注解类 | 说明 | | ————————— | ——————————————– | | @Null | 必须为 null | | @NotNull | 必须不为 null | | @AssertTrue | 必须为 true | | @AssertFalse | 必须为 false | | @Min(value) | 必须是一个数字,其值必须大于等于指定的最小值 | | @Max(value) | 必须是一个数字,其值必须小于等于指定的最大值 | | @DecimalMin(value) | 必须是一个数字,其值必须大于等于指定的最小值 | | @DecimalMax(value) | 必须是一个数字,其值必须小于等于指定的最大值 | | @Size(min, max) | 大小必须在指定的范围内 | | @Digits (integer, fraction) | 必须是一个数字,其值必须在可接受的范围内 | | @Past | 必须是一个过去的日期 | | @Future | 必须是一个将来的日期 | | @Pattern(value) | 必须符合指定的正则表达式 |

Hibernate-Validator提供的注解:

| 注解类 | 说明 | | ——— | ——————————— | | @Email | 必须是电子邮箱地址 | | @Length | 字符串的长度必须在指定的范围内 | | @NotEmpty | 必须非空(有空格就不算Empty) | | @NotBlank | 字符串的必须非空(单纯空格算Blank) | | @Range | 必须在指定范围内 |

  1. 编写控制器

    • 在控制器中的方法中,要使用 @Validated 注解,同时,要保证验证的对象与BindingResult 连在一起
     @Controller
     public class ValidatorController {
         
         @RequestMapping("/register2")
         public String testRegisterValidation(Model model,
                 @Validated UserDto userDto, BindingResult bindingResult) {
             //验证失败的信息会绑定到 bindingResult对象中,所以,我们要判断bindingResult
             if(bindingResult.hasErrors()) {
                 //
                 List<FieldError> errors = bindingResult.getFieldErrors();
                 for(FieldError fe : errors) {
                     System.out.println(fe.getField()+" => "+fe.getDefaultMessage());
                 }
                 //返回到当前页面
                 return "forward:/register2.jsp";
             }
             return "forward:/index.jsp";
         }
     }
    

    当然,我们也可以把这个错误信息包装好后绑定到model中,并在JSP页面中通过 EL表达式取出来。