一、JSR303
1.1 什么是JSR303
JSR303是Java规范请求(Java Specification Request)的编号,它定义了Java Bean验证的标准。Java Bean验证是一种验证框架,可以验证Java Bean中的属性,以确保它们符合特定的规则和约束。该框架在Java EE 6中得到了官方支持,并在javax.validation包中实现。JSR303规范定义了验证注释,这些注释可以应用于Java Bean的属性上,以指示验证规则。这些验证规则可以检查属性是否为空、是否符合正则表达式、是否在指定范围内等等。通过使用JSR303,我们可以确保Java Bean的属性始终符合预期,并在出现错误时及时捕获并处理这些错误。
JSR303的定义:
JSR303是一种Java平台标准,也称为Bean Validation,用于验证JavaBean和其他Java对象的声明约束。JSR303使用注释标记属性的限制,并提供了一个验证引擎,该引擎可以在运行时执行验证以确保对象的有效性。它提供了一种轻松的方式来验证表单数据和其他用户输入,防止不良数据进入应用程序。JSR303旨在提供一致的验证机制,使Java应用程序更加健壮和可维护。
1.2 为什么要使用JSR303
JSR303是Java Validation API的规范,它提供了一种简单易用的验证框架,帮助我们在实体类属性上进行验证,对于确保数据的正确性和完整性非常有用。 使用JSR303可以带来以下好处:
1. 易于维护和扩展:将验证规则注解到属性上,代码易于维护和扩展,避免了繁琐的手工验证。
2. 提高代码可读性:验证规则注解到属性上,代码可读性大大提高。
3. 减少重复代码:使用JSR303可以减少编写检验代码的重复工作,提高生产效率。
4. 提高系统健壮性:通过JSR303验证规则的定义,可以确保数据的正确性和完整性,提高系统健壮性和稳定性。
1.3 常用注解
JSR303是Java中的Bean Validation规范,其中定义了许多注解用于对JavaBean中的属性进行验证。以下是常用的JSR303注解及其解释:
1. @NotNull:验证字段不为null。
2. @NotBlank:验证字段不为空,即长度大于0,去掉空格后长度大于0。
3. @NotEmpty:验证字段不为空,即长度大于0。
4. @Min:验证数字字段的最小值。
5. @Max:验证数字字段的最大值。
6. @Size:验证字段的大小范围。
7. @DecimalMin:验证十进制数字段的最小值。
8. @DecimalMax:验证十进制数字段的最大值。
9. @Pattern:验证字段匹配正则表达式。
10. @Email:验证字段为Email格式。
11. @Length:验证字段的长度。
12. @Range:验证字段的值在范围内。
13. @Valid:验证嵌套对象。
14. @AssertTrue:验证字段为true。
15. @AssertFalse:验证字段为false。
16. @Past:验证日期字段在当前时间之前。
17. @Future:验证日期字段在当前时间之后。
以上是常用的JSR303注解及其解释,开发者可以根据实际情况选择需要的注解。
注@Validated与@Valid区别 ::
@Validated:
- Spring提供的
- 支持分组校验
- 可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上
- 由于无法加在成员属性(字段)上,所以无法单独完成级联校验,需要配合@Valid
@Valid:
- JDK提供的(标准JSR-303规范)
- 不支持分组校验
- 可以用在方法、构造函数、方法参数和成员属性(字段)上
- 可以加在成员属性(字段)上,能够独自完成级联校验
1.4 快速入门
1.4.1 导入依赖
<!-- JSR303 --> <hibernate.validator.version>6.0.7.Final</hibernate.validator.version> <!-- JSR303 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>${hibernate.validator.version}</version> </dependency>
1.4.2 配置校验规则
校验属性是否为空:
@NotNull(message = "歌曲编号不能为空") private Integer mid; @NotBlank(message = "歌曲名称不能为空") private String mname; @NotBlank(message = "歌曲专辑不能为空") private String mtype; @NotBlank(message = "歌曲歌词不能为空") private String minfo; @NotBlank(message = "歌曲图片不能为空") private String mpic = "暂无图片";
1.4.3 入门案例
在MusicController类中添加以下方法:
// 给数据添加服务端校验 @RequestMapping("/valiAdd") public String valiAdd(@Validated Music music, BindingResult result, HttpServletRequest req){ // 如果服务端验证不通过,有错误 if(result.hasErrors()){ // 服务端验证了实体类的多个属性,多个属性都没有验证通过 List<FieldError> fieldErrors = result.getFieldErrors(); Map<String,Object> map = new HashMap<>(); for (FieldError fieldError : fieldErrors) { // 将多个属性的验证失败信息输送到控制台 System.out.println(fieldError.getField() + ":" + fieldError.getDefaultMessage()); map.put(fieldError.getField(),fieldError.getDefaultMessage()); } req.setAttribute("errorMap",map); }else { this.musicBiz.insertSelective(music); return "redirect:list"; } return "mic/edit"; }
在服务端中进行校验,校验的模型的属性中出现错误,则将错误信息的属性进行遍历添加到map集合中并保存起来回显到前端,需要注意的是,注解@validated保存的是校验时的参数,最终校验的结果保存在BindingResult中.
1.4.4 结果测试
在没有进行后端效验前应该会报空指针异常。
但是在进行后端效验之后,就会将我们的错误信息反馈到前端的展示界面,如下:
控制台效果:
二、Java三大器之拦截器
2.1 什么是拦截器
2.1.1 定义
在Java编程中,拦截器(Interceptor)是一种常见的机制,它可以拦截方法的调用或者HTTP请求的处理过程,并在处理前后执行一些特定的操作或者逻辑。拦截器通常用于实现各种不同的功能,如权限控制、日志记录、事务管理等。
2.1.2 作用领域
在Java Web开发中,拦截器常用于拦截HTTP请求并进行处理,例如进行身份验证、拦截非法的请求、记录日志等。在Spring框架中,拦截器是一个非常重要的组件,可以通过实现HandlerInterceptor接口来定义拦截器,然后在配置文件中配置拦截器的拦截规则和执行顺序。在Struts2、Spring MVC等Web框架中也都有拦截器的支持。
2.2 Java三大器之过滤器
2.2.1 定义
Java中的过滤器(Filter)是一种用于拦截HTTP请求和响应的组件,它在请求到达Servlet之前拦截并验证HTTP请求,或在Servlet响应到达客户端前对响应进行处理。在Java Web应用中,过滤器是一个可配置的组件,它需要在web.xml文件中注册并配置相应的属性才能生效。可以通过编写实现javax.servlet.Filter接口的Java类来定义过滤器的功能。
2.2.2 作用领域
过滤器通常用于实现一些通用的处理逻辑,比如认证、日志记录、统计信息等,以提高代码复用性和可维护性。过滤器还可以用于跨站点脚本攻击(XSS)和跨站点请求伪造(CSRF)等安全机制的实现。
2.3 拦截器与过滤器的区别
图解如下:
拦截器和过滤器都是在Java Web开发中对请求进行拦截处理的一种工具,但是它们有以下区别:
1. 执行顺序: 过滤器是在Servlet容器调用servlet之前或之后执行的,而拦截器是在servlet处理请求之前或之后执行的。
2. 作用范围: 过滤器作用于所有的请求和响应,包括静态资源,而拦截器只拦截配置的路径及其子路径的请求。
3. 功能范围: 过滤器可以在过滤器链中做一些额外的功能,如字符编码、请求转发和重定向等,而拦截器可以更好地控制业务流程,如权限控制、日志记录等。
4. API不同: 过滤器是使用Servlet API实现的,而拦截器是使用Spring MVC框架自身的接口实现的。
总的来说,过滤器更加通用,可以实现一些基本的请求过滤和处理操作,而拦截器则更加灵活,可以根据业务需求实现更加复杂的操作。在实际应用中,需要根据具体的需求选择使用过滤器还是拦截器。
2.4 应用场景
- 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
- 权限检查:如登录检测,进入处理器检测是否登录,如果没有直接返回到登录页面;
- 性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
- 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个Controller中的处理方法都需要的,我们就可以使用拦截器实现。
2.5 拦截器工作原理
2.6 用户登录权限控制
基本拦截器配置(在Java目录下新建一个interceptor包,创建拦截器类):
OneInterceptor:
package com.Kissship.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class OneInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("【OneInterceptor】:preHandle..."); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("【OneInterceptor】:postHandle..."); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("【OneInterceptor】:afterCompletion..."); } }
TwoInterceptor:
package com.Kissship.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TwoInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("【TwoInterceptor】:preHandle..."); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("【TwoInterceptor】:postHandle..."); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("【TwoInterceptor】:afterCompletion..."); } }
然后在Spring-mvc.xml中配置多拦截器,添加代码如下:
<!--<!– 用户权限的请求拦截–>--> <mvc:interceptors> <bean class="com.Kissship.interceptor.LoginInterceptor"></bean> </mvc:interceptors> <mvc:interceptors> <!--2) 多拦截器(拦截器链)--> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.Kissship.interceptor.OneInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/mic/**"/> <bean class="com.Kissship.interceptor.TwoInterceptor"/> </mvc:interceptor> </mvc:interceptors>
然后接下来创建一个名为LoginInterceptor的拦截器,如下:
package com.Kissship.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("【implements】:preHandle..."); StringBuffer url = request.getRequestURL(); if (url.indexOf("/login") > 0 || url.indexOf("/logout") > 0){ // 如果是 登录、退出 中的一种 return true; } // 代表不是登录,也不是退出 // 除了登录、退出,其他操作都需要判断是否 session 登录成功过 String mname = (String) request.getSession().getAttribute("mname"); if (mname == null || "".equals(mname)){ response.sendRedirect("/page/login"); return false; } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
接着创建一个新的jsp页面用来充当登录界面进行效果测试,login.jsp代码如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>用户登入</title> </head> <body> <form action="${pageContext.request.contextPath }/login" method="post" enctype="multipart/form-data"> <label>用户名称:</label><br/> <input type="text" name="mname"/><br/> <input type="submit" value="登入"/> </form> </body> </html>
最后进行测试,效果如下:
最后SpringMVC之JSR303和拦截器就到这里,祝大家在敲代码的路上一路通畅!