文章目录
- 数据校验
- 自定义 Filter
- 自定义 Filter 两个步骤:
数据校验
在很多时候,当我们要处理一个应用程序的业务逻辑时,数据校验是必须要考虑和面对的事情。应用程序必须通过某种手段来确保输入进来的数据从语义上来讲是正确的。在 Java 应用程序中,必须要对输入进来的数据从语义上分析是有效的,也就是数据校验。
输入验证是最重要的 Web 开发任务之一,在 Spring MVC 中有两种方式可以验证输入:一种是 Spring 自带的验证框架,另外一种是利用 JSR 实现。
JSR 是一个规范文档,指定了一整套 API,通过标注给对象属性添加约束。Hibernate Validator 就是 JSR 规范的具体实现,Hibernate Validator 提供了 JSR 规范中所有内置约束注解的实现,以及一些附加的约束注解,除此之外用户还可以自定义约束注解。
Spring Boot 的参数校验依赖于 hibernate-validator 来进行。使用 Hibernate Validator 校验数据,需要定义一个接收的数据模型,使用注解的形式描述字段校验的规则,我们以 User 对象为例为大家演示如何使用。
首先在 WebController 添加一个保存的方法 saveUser,参数为 User。
@RequestMapping("/saveUser")
public void saveUser(@Valid User user,BindingResult result) {
System.out.println("user:"+user);
if(result.hasErrors()) {
List<ObjectError> list = result.getAllErrors();
for (ObjectError error : list) {
System.out.println(error.getCode()+ "-" + error.getDefaultMessage());
}
}
}
- @Valid 注解:参数前面添加 @Valid 注解,代表此对象使用了参数校验;
BindingResult 参数校验的结果会存储在此对象中,可以根据属性判断是否校验通过,校验不通过可以将错误信息打印出来。
接下来在 User 中给需要校验的参数添加对应的注解,对不同的属性,按照规则添加不同的校验内容。
public class User {
@NotEmpty(message="姓名不能为空")
private String name;
@Max(value = 100, message = "年龄不能大于100岁")
@Min(value= 18 ,message= "必须年满18岁!" )
private int age;
@NotEmpty(message="密码不能为空")
@Length(min=6,message="密码长度不能小于6位")
private String pass;
//...
}
其中,message=“密码不能为空”,为自定义返回的错误信息。
Hibernate Validator 基本上包含了常用的数据校验,包括校验属性是否为空、长度、大小、特定格式等,完整的注解可以看下表:
添加测试方法,对属性校验进行测试:
@Test
public void saveUsers() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/saveUser")
.param("name","")
.param("age","666")
.param("pass","test")
);
}
结果返回:
user:name=,age=666,pass=test
Max-年龄不能大于100岁
Length-密码长度不能小于6位
NotEmpty-姓名不能为空
结果显示均已经触发了校验规则,返回了错误信息,在实际使用过程中可以对错误信息进行包装,最后返回到前端进行展示。
自定义 Filter
Filter 也称之为过滤器,可以在前端拦截所有用户的请求,可以认为是 Servlet 的一种加强版,Web 开发人员通过 Filter 技术,对 Web 服务器管理的所有 Web 资源,例如 JSP、Servlet、静态图片文件或静态 HTML 文件等进行拦截,从而实现一些特殊的功能。例如,实现 URL 级别的权限访问控制、过滤敏感词汇、排除有 XSS 威胁的字符、记录请求日志等一些高级功能。
Spring Boot 内置了一些 Filter,比如,处理编码的 OrderedCharacterEncodingFilter 和请求转化的 HiddenHttpMethodFilter,也支持根据我们的需求来可以自定义 Filter。
自定义 Filter 有两种实现方式,第一种是使用 @WebFilter,第二种是使用 FilterRegistrationBean,经过实践之后发现使用 @WebFilter 自定义的过滤器优先级顺序不能生效,因此推荐使用第二个方案,接下来我们详细介绍第二种方案。
自定义 Filter 两个步骤:
实现 Filter 接口,实现其中的 doFilter() 方法;
添加 @Configuration 注解,将自定义 Filter 加入过滤链。
新建 MyFilter 类,重写 doFilter() 方法:
public class MyFilter implements Filter {
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain filterChain)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest request = (HttpServletRequest) srequest;
System.out.println("this is MyFilter,url :"+request.getRequestURI());
filterChain.doFilter(srequest, sresponse);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
将自定义 Filter 加入过滤链:
@Configuration
public class WebConfiguration {
@Bean
public FilterRegistrationBean testFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
registration.addUrlPatterns("/*");
registration.setName("MyFilter");
registration.setOrder(6);
return registration;
}
}
添加完后启动项目,在浏览器中输入地址:http://localhost:8080/getUsers,就会看到控制台打印如下信息:
this is MyFilter,url :/xxx
说明 MyFilter 已经对所有的 URL 进行了监控。当有多个过滤器时可以通过设置 Order 属性来决定它们的执行顺序,Order 值越小优先级越高。我们复制上面的 MyFilter 重命名为 MyFilter2,在 WebConfiguration 中添加 MyFilter2 的配置:
public FilterRegistrationBean test2FilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter2());
registration.addUrlPatterns("/*");
registration.setName("MyFilter2");
registration.setOrder(1);
return registration;
}
将 MyFilter 的 Order 属性设置为 6,将 MyFilter2 的 Order 属性设置为 1,重新启动项目,在浏览器中输入地址:http://localhost:8080/getUsers,就会看到控制台打印如下信息:
this is MyFilter2,url :/getUsers
this is MyFilter,url :/getUsers
可以发现过滤器 MyFilter2 因为 Order 值设置得低,会优先被执行。