SpringMVC中的JSR303与拦截器的使用

一,JSR303的概念

     JSR303是Java中的一个标准,用于验证和校验JavaBean对象的属性的合法性。它提供了一组用于定义验证规则的注解,如@NotNull、@Min、@Max等。在Spring MVC中,可以使用JSR303注解对请求参数进行校验。

1.2 为什么要使用JSR303?(更加理解)

前端不是已经校验过数据了吗?为什么我们还要做校验呢,直接用不就好了?草率了,假如说前端代码校验没写好又或者是对于会一点编程的人来说,直接绕过前端发请求(通过类似Postman这样的测试工具进行非常数据请求),把一些错误的参数传过来,你后端代码不就危险了嘛

所以我们一般都是前端一套校验,后端在一套校验,这样安全性就能够大大得到提升了。

1.3 常用的注解

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

1.4 @Validated与@Valid区别

@Validated:

  • Spring提供的

  • 支持分组校验

  • 可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上

  • 由于无法加在成员属性(字段)上,所以无法单独完成级联校验,需要配合@Valid

@Valid:

  • JDK提供的(标准JSR-303规范)

  • 不支持分组校验

  • 可以用在方法、构造函数、方法参数和成员属性(字段)上

  • 可以加在成员属性(字段)上,能够独自完成级联校验

 二,JSR303使用

2.1 导入pom.xml依赖

<!-- 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>

2.2 配置校验规则

package com.Bingzy.model;import lombok.ToString;
import org.hibernate.validator.constraints.NotBlank;@ToString
public class Tbook {@ToStringpublic class Clazz {@NotNull(message = "书籍编号不能为空")protected Integer bid;@NotBlank(message = "书籍名不能为空")protected String bname;@NotBlank(message = "书籍价格不能为空")protected Float price;public Clazz(String bid, String bname, Float price) {this.bid = bid;this.bname = bname;this.price = price;}public String getBid() {return bid;}public void setBid(String bid) {this.bid = bid;}public String getBname() {return bname;}public void setBname(String bname) {this.bname = bname;}public Float getPrice() {return price;}public void setPrice(Float price) {this.price = price;}@Overridepublic String toString() {return "Clazz{" +"bid='" + bid + '\'' +", bname='" + bname + '\'' +", price=" + price +'}';}}}

2.3 入门案例

在请求处理方法中,使用@Validated或@Valid注解要验证的对象,并根据BindingResult判断校验是否通过。

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

edit.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>博客的编辑界面</title>
</head>
<body>
<center>编辑界面<form action="${pageContext.request.contextPath }/${empty b ? 'book/valiAdd' : 'book/edit'}" method="post"><br>书籍id:<input type="text" name="bid" value="${b.bid }"><span style="color: red">${errorMap.bid}</span><br>书籍名称:<input type="text" name="bname" value="${b.bname }"><span style="color: red">${errorMap.bname}</span><br>书籍价格:<input type="text" name="price" value="${b.price }"><span style="color: red">${errorMap.price}</span><br><input type="submit"></form>
</center>
</body>
</html>

运行结果:

点击新增或修改,进入页面后点击提交显示相对应的提示语句 

 三,拦截器

3.1 什么是拦截器?

Spring MVC拦截器是Spring框架中的一个组件,用于拦截请求并在请求处理之前或之后执行一些额外的操作。它可以用于实现一些通用的、与业务无关的功能,如日志记录、权限验证、异常处理、跨域请求处理等。

拦截器在请求到达DispatcherServlet之后,但在具体的Controller方法执行之前,提供了一个拦截点,可以对请求进行处理和干预。拦截器可以拦截请求、响应或会话的各个阶段,并在每个阶段执行预定义的操作。

3.2 什么是过滤器

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

3.3 拦截器与过滤器的区别?

  • 过滤器(filter)

    1.filter属于Servlet技术,只要是web工程都可以使用

  • 2.filter主要由于对所有请求过滤

    3.filter的执行时机早于Interceptor

  • 拦截器(interceptor)

    1.interceptor属于SpringMVC技术,必须要有SpringMVC环境才可以使用

    2.interceptor通常由于对处理器Controller进行拦截

    3.interceptor只能拦截dispatcherServlet处理的请求

3.4 应用场景

  • 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。

  • 权限检查:如登录检测,进入处理器检测是否登录,如果没有直接返回到登录页面;

  • 性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);

  • 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个Controller中的处理方法都需要的,我们就可以使用拦截器实现

四,拦截器快速入门

定义一个包并创建OneInterceptor类

拦截器(interceptor):

package com.Bingzy.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;}@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...");}
}
  • spring-mvc.xml配置自定义拦截器

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

拦截器(interceptor)中的preHandle()方法中的返回值为true未拦截的情况:

拦截器(interceptor)中的preHandle()方法中的返回值为false拦截的情况: 

 注意:拦截器会根据preHandle()方法返回值进行拦截判断,返回了一个true值。这个返回值表示该拦截器已经处理了当前的请求,并且可以继续向下传递请求。如果返回false,则表示该拦截器不处理当前请求,请求将被终止 

4.1 拦截器原理图

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

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

    方法参数

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

  • postHandle:用于对拦截到的请求进行后处理,可以在方法中对模型数据和视图进行修改

    执行时机:在处理器的方法执行后,视图渲染之前

    方法参数

    参数说明
    request请求对象
    response响应对象
    handler拦截到的处理器方法
    ModelAndView处理器方法返回的模型和视图对象,可以在方法中修改模型和视图

  • afterCompletion:用于在整个流程完成之后进行最后的处理,如果请求流程中有异常,可以在方法中获取对象

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

    方法参数

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

4.2 拦截器链

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

拦截器(interceptor)

package com.Bingzy.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.Bingzy.interceptor.OneInterceptor"/></mvc:interceptor><mvc:interceptor><mvc:mapping path="/book/**"/><bean class="com.Bingzy.interceptor.TwoInterceptor"/></mvc:interceptor>
</mvc:interceptors>

运行展示:

五,用户登录权限案例 

登入拦截器(interceptor):

package com.Bingzy.interceptor;import org.springframework.web.servlet.HandlerInterceptor;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 bname = (String) request.getSession().getAttribute("bname");if (bname == null || "".equals(bname)){response.sendRedirect("/page/book/login");return false;}return true;}}

spring-mvc.xml配置自定义登入拦截器

<mvc:interceptors><bean class="com.Bingzy.interceptor.LoginInterceptor"></bean>
</mvc:interceptors>

Controller层(web):

package com.Bingzy.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 bname = req.getParameter("bname");HttpSession session = req.getSession();if ("zs".equals(bname)){session.setAttribute("bname",bname);}return "redirect:/book/list";}@RequestMapping("/logout")public String logout(HttpServletRequest req){req.getSession().invalidate();return "redirect:/book/list";}
}

login.jsp:

简单的测试布局,可自行布局

测试结果:

 

总结

   如果用户发送URL中的后缀包含"/login"或"/logout",则表示当前请求是登录或退出操作,直接返回true表示继续处理请求,后端进行判断“uname”是否为“zs”,如果不是zs则域对象不会保存,从而到拦截器判断域对象为空则会重定向到登良页面,如果不为空就执行后端返回的字符串到视图解析器解析跳转指定页面

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

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

相关文章

深度学习-卷积神经网络-纹理表示卷积神经网络-卷积神经网络-[北邮鲁鹏]

这里写目录标题 参考文章全连接神经网络全连接神经网络的瓶颈全连接神经网络应用场景 卷积神经网络卷积层(CONV)卷积核卷积操作卷积层设计卷积步长(stride)边界填充特征响应图组尺寸计算 激活层池化层(POOL)池化操作定义池化操作作用池化层超参数常见池化操作 全连接层(FC)样本…

【看好了】如何使用fiddler实现手机抓包,Filters过滤器!

一、Fiddler与其他抓包工具的区别  1、Firebug虽然可以抓包&#xff0c;但是对于分析http请求的详细信息&#xff0c;不够强大。模拟http请求的功能也不够&#xff0c;且firebug常常是需要“无刷新修改”&#xff0c;如果刷新了页面&#xff0c;所有的修改都不会保存&#xff…

文安县人社局 举办“情暖灾区 就业护航”直播带岗活动

关于防汛救灾工作重要指示精神&#xff0c;助力受灾企业尽快复工复产、受灾群众尽早实现就业。9月15日&#xff0c;文安县人力资源和社会保障局联合文安县总工会、国家税务总局文安县税务局共同举办文安县助力企业灾后重建“直播带岗”活动。 本次活动以“情暖灾区 就业护航”…

IDEA中DEBUG技巧

Debug 介绍 Debug 设置 如上图标注 1 所示&#xff0c;表示设置 Debug 连接方式&#xff0c;默认是 Socket。Shared memory 是 Windows 特有的一个属性&#xff0c;一般在 Windows 系统下建议使用此设置&#xff0c;相对于 Socket 会快点。 ## Debug 常用快捷键 Win 快捷键M…

分享一个Python 写的监控日志log txt文档 的代码

监控log文件的需求 某些特殊原因&#xff0c;想一直看到.log 的最后一行打印&#xff0c;所以写了一些代码监控log &#xff08;有个奇怪需求&#xff0c;就是log 因为重复启动原因&#xff0c;会一直加&#xff0c;不是同一个log&#xff09; 监控界面 涉及的Python代码&…

Unity SteamVR 开发教程:用摇杆/触摸板控制人物持续移动(2.x 以上版本)

文章目录 &#x1f4d5;教程说明&#x1f4d5;场景搭建&#x1f4d5;创建移动的动作&#x1f4d5;移动脚本⭐移动⭐实时调整 CharacterController 的高度 &#x1f4d5;取消手部和 CharacterController 的碰撞 持续移动是 VR 开发中的一个常用功能。一般是用户推动手柄摇杆&…

CNN(八):Inception V1算法实战与解析

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客 &#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 1 Inception V1 Inception v1论文 1.1 理论知识 GoogLeNet首次出现在2014年ILSVRC比赛中获得冠军。这次的版本通常称其为Inception V1。…

strncpy

strncpy&#xff1a; 函数介绍&#xff1a; 函数原型&#xff1a; char *strncpy(char *dest, const char *src, int n) 返回值&#xff1a;dest字符串起始地址 说明&#xff1a; 1、当src字符串长度小于n时&#xff0c;则拷贝完字符串后&#xff0c;剩余部分将用空字节填…

建站系列(八)--- 本地开发环境搭建(WNMP)

目录 相关系列文章前言一、准备工作二、Nginx安装三、MySQL安装四、PHP安装及Nginx配置五、总结 相关系列文章 建站系列&#xff08;一&#xff09;— 网站基本常识 建站系列&#xff08;二&#xff09;— 域名、IP地址、URL、端口详解 建站系列&#xff08;三&#xff09;— …

【设计模式】二、UML 类图概述

文章目录 常见含义含义依赖关系&#xff08;Dependence&#xff09;泛化关系&#xff08;Generalization&#xff09;实现关系&#xff08;Implementation&#xff09;关联关系&#xff08;Association&#xff09;聚合关系&#xff08;Aggregation&#xff09;组合关系&#x…

【JavaScript保姆级教程】输出函数和初识变量

文章目录 前言一、输出内容1.1 document.write()函数1.2 console.log()函数查看终端输出信息 1.3 alert()函数 二、变量的使用1.1 变量的声明1.3变量的赋值1.4 变量的声明和赋值 三、输入提示框的使用总结 前言 JavaScript是一种强大的脚本语言&#xff0c;广泛应用于网页开发…

文件批量重命名:自定义命名与扩展名更改

你是否曾经需要批量更改文件名称和类型&#xff1f;如果你有大量文件需要重命名和更改类型&#xff0c;那么今天我们将向你介绍一种简单的方法来轻松批量更改文件名称和类型。无论你是需要将一个文件夹中的所有图片改为另一种格式&#xff0c;还是需要将一个文件夹中的所有文档…

【基于多输出方向的同步异步日志系统】

本项目涉及的到所有源码见以下链接&#xff1a; https://gitee.com/ace-zhe/wz_log 一、项目简介 1.日志的概念&#xff08;白话版&#xff09; 日志类似于日记&#xff0c;通常是指对完成某件事情的过程中状态等的记录&#xff0c;而计算机中的日志是指日志数据&#xff0c…

轻松学习 Spring 事务

文章目录 一. Spring事务简介二. Spring事务使用1. 编程式事务2. 声明式事务 三. Transactional的使用1. 参数作用2. 事务失效的场景3. Transactional工作原理 四. Spring 事务的隔离级别五. Spring事务传播机制 一. Spring事务简介 在之前的博客已经介绍了在 Spring 环境中整…

结构体变量的初始化和引用

任务描述 本关任务&#xff1a;从键盘输入两个学生的学号&#xff0c;姓名和成绩&#xff08;整数&#xff09;&#xff0c;分别存入结构体中&#xff0c;输出成绩较高的学生的学号&#xff0c;姓名和成绩。 相关知识 结构体类型用于描述由多个不同数据类型的数据构成的复合…

浅析安防监控系统/AI视频智能分析算法:河道水文水位超标算法应用

传统的水位水尺刻度尺位监测中&#xff0c;所采用的人工读数方式&#xff0c;效率较为低下且 人工成本较高&#xff0c;不利于作业流程的数字化。尽管感应器检测会自动对水位的模拟输入进行筛选&#xff0c;但是由于成本、使用场景要求高、后续日常维护复杂等多种因素&#xff…

Pytorch实现图像语义分割(初体验)

Pytorch实现图像语义分割&#xff08;初体验&#xff09; 这些天在学习图像语义分割相关的知识&#xff0c;并简单写了篇概述。原本想先看几篇经典论文&#xff0c;如全卷积网络FCN&#xff0c;奈何英语水平有限&#xff0c;翻译起来实在费劲。想来不如先直接体验一下语义分割…

vscode c++解决包含头文件红色波浪线问题

安装c/c插件后&#xff0c;按ctrlshiftp&#xff0c; 点击打开了c_cpp_properties.json文件&#xff0c;对其中的IncludePath进行编辑&#xff0c;示例如下&#xff1a; "includePath": ["${workspaceFolder}/**","${workspaceFolder}/include/**&q…

Gin 打包vue或react项目输出文件到程序二进制文件

Gin 打包vue或react项目输出文件到程序二进制文件 背景解决方案1. 示例目录结构2. 有如下问题要解决:3. 方案探索 效果 背景 前后端分离已成为行业主流&#xff0c;vue或react等项目生成的文件独立在一个单独目录&#xff0c;与后端项目无关。 实际部署中&#xff0c;通常前面套…

JDK9特性——模块化REPL工具

文章目录 前言模块化模块化案例 可交互的REPL工具 前言 谈到Java9大家往往第一个想到的就是Jigsaw项目&#xff08;后改名为Modularity&#xff09;。众所周知&#xff0c;Java已经发展超过20年(95年最初发布)&#xff0c;Java和相关生态在不断丰富的同时也越来越暴露出一些问…