【SpringMVC】JSR 303与interceptor拦截器快速入门

目录

一、JSR303

1、什么是JSR 303?

2、为什么要使用JSR 303?

3、JSR 303常用注解

3.1、常用的JSR 303注解

3.2、@Validated与@Valid区别

3.2.1、@Validated

3.2.2、@Valid

3.2.3、区别

4、使用案例

4.1、导入依赖

4.2、配置校验规则

4.3、编写校验方法

4.4、前端代码

4.5、测试

二、interceptor拦截器

1、什么是拦截器?

2、为什么要使用拦截器?

3、拦截器与过滤器

 3.1、什么是过滤器(Filter)

3.2、拦截器与过滤器的区别

3.2.1、 过滤器(filter)

3.2.2、 拦截器(interceptor)

3.2.3、汇总

4、拦截器应用场景

5、使用案例

5.1、创建拦截器

5.2、配置拦截器

5.3、运行测试

5.4、拦截器工作原理

5.5、拦截器链

5.6、登录拦截实例

5.6.1、创建拦截器

5.6.2、配置拦截器

5.6.3、编写控制层

5.6.4、前端页面

5.6.5、测试

登入

登出


一、JSR303

1、什么是JSR 303?

JSR 303是Java规范请求(Java Specification Request)的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。 JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean ValidationHibernate Validator Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint(约束) 的实现,除此之外还有一些附加的 constraint。

它定义了一套用于Java Bean校验的标准。JSR 303使用注解的方式,在Spring MVC中被广泛应用于进行数据校验和验证。

验证数据是一项常见任务,它发生在从表示层到持久层的所有应用程序层中。通常在每一层都实现相同的验证逻辑,这既耗时又容易出错。为了避免重复这些验证,开发人员经常将验证逻辑直接捆绑到域模型中,将域类与验证代码混在一起,而验证代码实际上是关于类本身的元数据

2、为什么要使用JSR 303?

        在前端我们进行了数据校验,可是为什么我们还要做一篇,因为因为一点小失误我们的前端校验没有写好,但是有些人还是会绕过前端发送的请求(通过类似Postman这样的测试工具进行非常数据请求),传递一些错误的参数,这就会让我们的后端代码有大大的危险,所以我们一般都是前端一套校验,后端在一套校验,这样安全性就能够大大得到提升了。

所以我总和了JSR 303以下的好处:

  1. 提高代码的可维护性:通过在实体类中添加注解,可以清晰地标识出需要进行校验的字段和规则,使代码更易于理解和维护。
  2. 增强数据的完整性:根据定义的规则,可以自动校验输入数据的合法性,避免错误数据进入系统,保证数据的完整性和准确性。
  3. 减少重复代码:通过注解,可以在不同场景下重复使用相同的校验规则,减少编写重复代码的工作量。

3、JSR 303常用注解

3.1、常用的JSR 303注解

注解 说明 @Null 用于验证对象为null @NotNull 用于对象不能为null,无法查检长度为0的字符串 @NotBlank 只用于String类型上,不能为nulltrim()之后的size>0 @NotEmpty 用于集合类、String类不能为null,且size>0。但是带有空格的字符串校验不出来 @Size 用于对象(Array,Collection,Map,String)长度是否在给定的范围之内 @Length 用于String对象的大小必须在指定的范围内 @Pattern 用于String对象是否符合正则表达式的规则 @Email 用于String对象是否符合邮箱格式 @Min 用于NumberString对象是否大等于指定的值 @Max 用于NumberString对象是否小等于指定的值 @AssertTrue 用于Boolean对象是否为true @AssertFalse 用于Boolean对象是否为false

3.2、@Validated与@Valid区别

@Validated @Valid 是用于数据校验的注解,但它们有一些区别和应用场景的差异。

3.2.1、@Validated

  • Spring 框架提供的注解
  • 支持分组校验
  • 可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上
  • 由于无法加在成员属性(字段)上,所以无法单独完成级联校验需要配合@Valid
  • Spring 提供的校验器,默认使用的是 Hibernate Validator(实现了 JSR-303 规范),但它支持更丰富的校验场景,如分组校验。

3.2.2、@Valid

  • JDK提供的 JSR-303(Bean Validation)规范的注解
  • 不支持分组校验
  • 可以用在方法、构造函数、方法参数和成员属性(字段)上
  • 可以加在成员属性(字段)上,能够独自完成级联校验
  • 使用 @Valid 注解时,会触发 JSR-303 或者其它支持的校验框架来对被注解的对象进行校验。

3.2.3、区别

  1. 适用范围@Valid 可以应用于方法参数、返回值、字段和方法上,而 @Validated 只能应用于类、接口和方法上。
  2. 校验框架@Validated 默认使用 Hibernate Validator(实现了 JSR-303)、Spring Validator 或自定义的校验器,而 @Valid 使用的是 JSR-303 或其它支持的校验框架。
  3. 分组校验@Validated 支持分组校验,允许在不同的场景下使用不同的校验规则,而 @Valid 不直接支持分组校验。

@Validated 是 Spring 框架提供的扩展注解,并不属于 Java 标准规范。在使用时,可以根据具体的需求选择合适的注解进行数据校验。

4、使用案例

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>

4.2、配置校验规则

在实体类里面添加配置校验

package com.tgq.model;import lombok.ToString;
import org.hibernate.validator.constraints.NotBlank;import javax.validation.constraints.NotNull;@ToString
public class MyStudent {@NotNull(message = "学生编号不能为空")private String sid;@NotBlank(message = "学生名不能为空")private String sname;@NotBlank(message = "学生年龄不能为空")private String sage;@NotBlank(message = "学生性别不能为空")private String ssex;public MyStudent(String sid, String sname, String sage, String ssex) {this.sid = sid;this.sname = sname;this.sage = sage;this.ssex = ssex;}public MyStudent() {super();}public String getSid() {return sid;}public void setSid(String sid) {this.sid = sid;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}public String getSage() {return sage;}public void setSage(String sage) {this.sage = sage;}public String getSsex() {return ssex;}public void setSsex(String ssex) {this.ssex = ssex;}
}

4.3、编写校验方法

   使用@Validated注解对我们的MyStudent进行服务端校验。

    //    给数据添加服务端校验@RequestMapping("/valiAdd")public String valiAdd(@Validated MyStudent myStudent, 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.myStudentBiz.insertSelective(myStudent);return "redirect:stu/list";}return "stu/edit";}

4.4、前端代码

使用form表单进行提交

<%--Created by IntelliJ IDEA.User: tgqDate: 12/9/2023Time: 下午8:05To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>edit</title>
</head>
<body><form action="${pageContext.request.contextPath }/stu/valiAdd" method="post">用户id:<input type="text" name="sid"><span style="color: red">${errorMap.sid}</span><br>用户名:<input type="text" name="sname"><span style="color: red">${errorMap.sname}</span><br>用户年龄:<input type="text" name="sage"><spanstyle="color: red">${errorMap.sage}</span><br>用户性别:<input type="text" name="ssex"><span style="color: red">${errorMap.ssex}</span><br><input type="submit" value="提交">
</form>
</body>
</html>

4.5、测试

点击提交,如果为空就会提示

二、interceptor拦截器

1、什么是拦截器?

        拦截器是在请求进入后端处理程序之前或之后执行特定逻辑的组件。它们能够拦截处理程序执行的流程,允许在请求处理过程中插入额外的功能。

        SpringMVC的处理器拦截器,类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。依赖于web框架,在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用

2、为什么要使用拦截器?

  1. 横向功能扩展:通过拦截器,可以在不修改原有业务逻辑的情况下添加额外的功能,例如日志记录、权限验证、性能统计等。
  2. 代码复用:多个请求中可能需要相同的处理逻辑,通过拦截器可以将这部分逻辑抽取出来,减少代码的重复编写。
  3. 解耦合:通过拦截器,可以将关注点分离,在拦截器中处理通用的逻辑,使得业务处理程序更专注于业务本身。

3、拦截器与过滤器

 3.1、什么是过滤器(Filter)

依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等。

3.2、拦截器与过滤器的区别

3.2.1、 过滤器(filter)

  1.   filter属于Servlet技术,只要是web工程都可以使用
  2.   filter主要由于对所有请求过滤
  3.   filter的执行时机早于Interceptor

3.2.2、 拦截器(interceptor)

  1.   interceptor属于SpringMVC技术,必须要有SpringMVC环境才可以使用
  2.   interceptor通常由于对处理器Controller进行拦截
  3.   interceptor只能拦截dispatcherServlet处理的请求

3.2.3、汇总

  • 拦截器是在应用程序处理程序内部执行的,而过滤器则是在应用程序之前或之后执行的。
  • 过滤器是基于Servlet规范的,拦截器是基于应用框架的。
  • 过滤器可以在请求到达Servlet容器之前对请求进行处理,而拦截器只能在请求到达应用程序之后进行处理。

4、拦截器应用场景

  1. 权限验证:拦截器可以检查用户是否具有操作的权限,如果没有权限,可以拦截请求并返回相应的错误信息。如果没有直接返回到登录页面。
  2. 日志记录:拦截器可以记录请求的详细信息,例如请求时间、信息、请求参数等,便于后续的日志分析和故障排查。以便进行信息监控、信息统计、计算PV(Page View)等。
  3. 性能统计:拦截器可以统计请求的执行时间,便于分析系统性能并进行优化。(如果有反向代理,如apache可以自动记录);
  4. 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个Controller中的处理方法都需要的,我们就可以使用拦截器实现。

拦截器链是由多个拦截器组成的链式结构,每个拦截器都可以在请求处理程序执行之前或之后进行特定的操作。拦截器链中的拦截器按照预定义的顺序执行,每个拦截器都有机会处理请求和响应。拦截器链可以保证各个拦截器的有序执行,以达到预期的处理逻辑。

5、使用案例

5.1、创建拦截器

创建一个拦截器的包,在包下创建拦截器

package com.tgq.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 {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("【OneInterceptor】:preHandle...");return true;//返回true / false}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("【OneInterceptor】:postHandle...");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("【OneInterceptor】:afterCompletion...");}
}

5.2、配置拦截器

在我们的自己配置spring-mvc.xml里面配置我们的拦截器

<mvc:interceptors><bean class="com.tgq.interceptor.OneInterceptor"></bean></mvc:interceptors>

5.3、运行测试

启动项目,打开浏览器访问请求地址,测试拦截器的拦截效果。

他们的执行顺序为:preHandle --> postHandle --> afterCompletion

http://localhost:8080/sc/list

5.4、拦截器工作原理

  • preHandle:用于对拦截到的请求进行预处理,方法接收布尔(true,false)类型的返回值,返回true:放行,false:不放行。

执行时机:在处理器方法执行前执行

方法参数
参数说明
request      请求对象    
response    响应对象    
handler      拦截到的处理器方法  
ModelAndView处理器方法返回的模型和视图对象,可以在方法中修改模型和视图
  • afterCompletion:用于在整个流程完成之后进行最后的处理,如果请求流程中有异常,可以在方法中获取对象

  执行时机:视图渲染完成后(整个流程结束之后)

方法参数
参数说明
request  请求参数
response响应对象  
handler  拦截到的处理器方法
ex异常对象

5.5、拦截器链

如果多个拦截器能够对相同的请求进行拦截,则多个拦截器会形成一个拦截器链,主要理解拦截器链中各个拦截器的执行顺序。拦截器链中多个拦截器的执行顺序,根拦截器的配置顺序有关,先配置的先执行。

package com.tgq.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 {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("【TwoInterceptor】:preHandle...");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("【TwoInterceptor】:postHandle...");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("【TwoInterceptor】:afterCompletion...");}
}

配置spring-mvc.xml

<mvc:interceptors><!--2) 多拦截器(拦截器链)--><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.tgq.interceptor.OneInterceptor"/></mvc:interceptor><mvc:interceptor><mvc:mapping path="/sc/**"/><bean class="com.tgq.interceptor.TwoInterceptor"/></mvc:interceptor></mvc:interceptors>

走一个拦截器:editicon-default.png?t=N7T8http://localhost:8080/stu/save

走两个拦截器:列表icon-default.png?t=N7T8http://localhost:8080/sc/list

5.6、登录拦截实例

5.6.1、创建拦截器

package com.tgq.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 {@Overridepublic 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 sname = (String) request.getSession().getAttribute("sname");if (sname == null || "".equals(sname)) {response.sendRedirect("/page/stu/login");return false;}return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

5.6.2、配置拦截器

    <!--登录拦截器实例--><mvc:interceptors><bean class="com.tgq.interceptor.LoginInterceptor"></bean></mvc:interceptors>

5.6.3、编写控制层

package com.tgq.web;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;@Controller
public class LoginController {@RequestMapping("/login")public String login(HttpServletRequest req) {String sname = req.getParameter("sname");HttpSession session = req.getSession();if ("tgq".equals(sname)) {session.setAttribute("sname", sname);}return "redirect:/sc/list";}@RequestMapping("/logout")public String logout(HttpServletRequest req) {req.getSession().invalidate();return "redirect:/sc/list";}
}

5.6.4、前端页面

<%--Created by IntelliJ IDEA.User: tgqDate: 12/9/2023Time: 下午10:03To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>用户登录</title>
</head>
<body><form action="/login" method="post">账号:<input name="sname"><input type="submit">
</form>
</body>
</html>

5.6.5、测试

登入

http://localhost:8080/logouticon-default.png?t=N7T8http://localhost:8080/login

登出

http://localhost:8080/logouticon-default.png?t=N7T8http://localhost:8080/logout

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/110172.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

去耦电路设计应用指南(二)电容的噪声抑制

&#xff08;二&#xff09;电容的噪声抑制 1. 电容的频率特性1.1 MLCC1.2 LW逆转电容1.3 三端子电容 2. 电容layout3. 电容安装位置与干扰路径4. 多个电容并联及反谐振 由于电容自身的频率特性以及器件在 PCB 上面的 layout&#xff0c;在噪声抑制的效果也会受到影 响&#xf…

智慧公厕建设的好处

在现代社会的迅猛发展中&#xff0c;智慧公厕的建设越来越受到重视。通过智慧高效管理和保持公厕整洁&#xff0c;城市形象得以提升&#xff0c;为居民提供更加便捷舒适的生活服务。本文将以智慧公厕源头厂家广州中期科技有限公司&#xff0c;大量精品项目案例&#xff0c;实景…

关系型三大范式与BCNF有什么用呢

学的时候就知道是一堆公式。 实际中在设计表的时候可能会用到。 前提是关系型数据库&#xff0c;比如mysql。 &#xff08;实际中oracle比mysql更好用。但是他收费啊。&#xff09; 第一范式&#xff1a;每个属性都是原子的&#xff08;需要做到每个属性都是不可分割的。&…

LeetCode 2596. 检查骑士巡视方案

【LetMeFly】2596.检查骑士巡视方案 力扣题目链接&#xff1a;https://leetcode.cn/problems/check-knight-tour-configuration/ 骑士在一张 n x n 的棋盘上巡视。在有效的巡视方案中&#xff0c;骑士会从棋盘的 左上角 出发&#xff0c;并且访问棋盘上的每个格子 恰好一次 。…

Python3.10 IDLE更换主题

前言 自定义主题网上有很多&#xff0c;3.10IDLE的UI有一些新的东西&#xff0c;直接扣过来会有些地方覆盖不到&#xff0c;需要自己测试着添几行配置&#xff0c;以下做个记录。 配置文件路径 Python安装目录下的Lib\idlelib\config-highlight.def。如果是默认安装&#xf…

【JVM 内存结构丨堆】

堆 定义内存分配特点:分代结构对象分配过程Full GC /Major GC 触发条件引用方式堆参数堆内存实例 主页传送门&#xff1a;&#x1f4c0; 传送 定义 JVM&#xff08;Java Virtual Machine&#xff09;堆是Java应用程序运行时内存管理的重要组成部分之一。堆内存用于存储Java对象…

vue学习之vue cli创建项目

安装 node.js https://nodejs.org/en 安装 vue cli npm install -g @vue/cli --registry=https://registry.npm.taobao.org创建项目 执行创建命令,回车vue create vue-cli-learning选择 “Manually select features”,回车 “空格” 关闭 Linter / Formatter 选项,回车

android注解之APT和javapoet

前言 前面我们已经讲过注解的基本知识&#xff0c;对于注解还不太了解的&#xff0c;可以去看一下之前的文章&#xff0c; android 注解详解_袁震的博客-CSDN博客。 之前我们在讲注解的时候&#xff0c;提到过APT和JavaPoet&#xff0c;那么什么是APT和JavaPoet呢&#xff1…

【ChatGPT原理与实战】4个维度讲透ChatGPT技术原理,揭开ChatGPT神秘技术黑盒!

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;陈童学哦&#xff0c;目前学习C/C、算法、Python、Java等方向&#xff0c;一个正在慢慢前行的普通人。 &#x1f3c0;系列专栏&#xff1a;陈童学的日记 &#x1f4a1;其他专栏&#xff1a;CSTL&…

Cesium 地球网格构造

Cesium 地球网格构造 Cesium原理篇&#xff1a;3最长的一帧之地形(2&#xff1a;高度图) HeightmapTessellator 用于从高程图像创建网格。提供了一个函数 computeVertices&#xff0c;可以根据高程图像创建顶点数组。 该函数的参数包括高程图像、高度数据的结构、网格宽高、…

网络安全深入学习第四课——热门框架漏洞(RCE— Log4j2远程代码执行)

文章目录 一、log4j2二、背景三、影响版本四、漏洞原理五、LDAP和JNDI是什么六、漏洞手工复现1、利用DNSlog来测试漏洞是否存在2、加载恶意文件Exploit.java&#xff0c;将其编译成class文件3、开启web服务4、在恶意文件Exploit.class所在的目录开启LDAP服务5、监听反弹shell的…

SEO优化排名的技巧与注意点(百度SEO排名的五大注意点)

关键词排名是指在搜索引擎中&#xff0c;用户搜索相关关键词时&#xff0c;网站出现的顺序。SEO优化是提高网站排名的一种方法。优化关键词排名的目的是提高网站流量和知名度。但是要注意遵循百度SEO排名的规则。 下面介绍一下百度SEO排名的五大注意点和优化关键词的六种方式。…