SpringMVC中的JSR303与拦截器的使用

news2024/11/24 17:23:01

一,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 {

    @ToString
    public 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;
        }

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

<mvc:interceptors>
        <bean class="com.zking.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 {
    @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>
        <!--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 {
    @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 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.coloradmin.cn/o/1005689.html

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

相关文章

2023年墨西哥 SP/BMV IPC 研究报告

第一章 指数概况 1.1 指数基本情况 墨西哥 S&P/BMV IPC 指数衡量在墨西哥证券交易所 (Bolsa Mexicana de Valores, BMV)上市&#xff0c;规模最大、流动性最高的股票表现。提供一个覆盖墨西哥股市的广泛、具有代表性且可轻易复制的指数。根据多元化要求&#xff0c;按市值…

Redis哨兵Cluster群集 搭建

Redis群集 Redis群集有三种模式 主从同步/复制哨兵模式Cluster群集 主从同步/复制 概念 主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份&#xff0c;以及对于读操作的负载均衡和简单的故障恢复缺陷…

ENVI_IDL: 基础语法详解

01 题目 02 代码说明 题目本身很简单&#xff0c;但是我自己加了一些东西进去增加难度。主要包括print函数的封装、格式化字符串&#xff0c;但是不影响代码的阅读。&#xff08;注&#xff1a;对于没有语言基础的人而言相对阅读困难&#xff0c;但是由于IDL是解释型语言&…

文字点选验证码识别(下)-训练一个孪生神经网络模型

声明 本文以教学为基准、本文提供的可操作性不得用于任何商业用途和违法违规场景。 本人对任何原因在使用本人中提供的代码和策略时可能对用户自己或他人造成的任何形式的损失和伤害不承担责任。 如有侵权,请联系我进行删除。 文章中没有代码,只有过程思路,请大家谨慎订阅。…

Windows下的Elasticsearch-head安装

Windows下的Elasticsearch-head安装 参考&#xff1a;https://gitcode.net/mirrors/mobz/elasticsearch-head 需要用到 npm 命令&#xff0c;这里可以提前下载安装下Node.js 即可自动安装npm&#xff1b; Node.js 下载安装地址&#xff1a;https://nodejs.org/en/download # 进…

【Unity每日一记】音频,麦克风,粒子和拖尾渲染器

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

LCD1602液晶显示屏介绍和程序开发

1.LCD1602概述 LCD1602&#xff08;Liquid Crystal Display&#xff09;是一种工业字符型液晶&#xff0c;能够同时显示 1602 即 32 字符(16列两行) 引脚说明第 1 脚: VSS 为电源地第 2 脚: VDD 接 5V 正电源第 3 脚: VL 为液晶显示器对比度调整端,接正电源时对比度最弱&…

华为云云耀云服务器L实例评测| ultralytics最先进模型YOLOv8深度学习AI训练

目录 前言 登录服务器 安装pyhton 部署yolov8 安装Pytorch 下载权重文件 训练模型 前言 前几期我们在云耀云服务器L实例上分别使用docker和直接在centos上部署了yolov5识别API&#xff0c;前端项目vue&#xff0c;后端项目.net Core Web Api,但是从监控图上来看&#…

联网汽车和网络犯罪:入门

正在权衡如何投资预算的原始设备供应商 ( OEM ) 及其供应商可能倾向于放慢应对网络威胁的投资。迄今为止&#xff0c;他们遇到的攻击仍然相对简单&#xff0c;危害性也不是特别大。 然而&#xff0c;对地下犯罪信息交换中的聊天记录的分析表明&#xff0c;这些碎片的存在是为了…

html5学习笔记22-JavaScript 简略学习

https://www.runoob.com/js/js-tutorial.html JavaScript 是 Web 的编程语言。与java无关。 案例&#xff1a;https://c.runoob.com/examples/ JavaScript 是一种轻量级的编程语言、可插入 HTML 页面的编程代码、脚本语言。 ECMA-262 是 JavaScript 标准的官方名称。 HTML 中的…

房地产小程序 | 小程序赋能,房地产业务数字化升级

随着科技的不断发展&#xff0c;房地产行业正逐渐向数字化转型。在这个过程中&#xff0c;房地产小程序成为了一种重要的工具&#xff0c;可以帮助房地产企业提供更好的购房体验、增加销售额&#xff0c;并实现管理的便捷化。 优点 便捷购房体验&#xff1a;房地产小程序为用户…

vite + react + typescript + uni-app + node 开发一个生态系统

简介 使用 vite react typescript uni-app node 来开发一个简易的生态系统案例&#xff0c;包含 APP&#xff0c;H5&#xff0c;微信小程序&#xff0c;控制台&#xff0c;服务端 开发 admin 技术栈&#xff1a;vite react typescript初始化控制台项目选择自定义预设…

快速傅里叶变化

引言 目标 傅里叶变化&#xff08;Fourier transform&#xff09;是一种信号处理技术&#xff0c;它可以将时间信号转换为频率信号&#xff0c;即将一组具有相同数量频率的正弦波叠加在一起&#xff0c;形成一组新的正弦波。如果我们把时间信号从频域转换到时域&#xff0c;那么…

手搭手入门MybaitsX

Mybatis-Plus介绍 为简化开发而生 MyBatis-Plus(opens new window)&#xff08;简称 MP&#xff09;是一个 MyBatis(opens new window) 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 特性 无侵入&#xff1a;只做增强…

2022年全国研究生数学建模竞赛华为杯C题汽车制造涂装-总装缓存调序区调度优化问题求解全过程文档及程序

2022年全国研究生数学建模竞赛华为杯 C题 汽车制造涂装-总装缓存调序区调度优化问题 原题再现&#xff1a; 背景介绍   汽车制造厂主要由焊装车间、涂装车间、总装车间构成&#xff0c;每个车间有不同的生产偏好&#xff0c;如&#xff1a;焊装车间由于车身夹具的限制偏向最…

【C语言】指针的“最后一站”【进阶版】

欢迎各位看官^_^ 目录 1、字符指针 2、指针数组 3、数组指针 3.1数组指针的定义 3.2数组指针的使用 4、数组指针和指针数组的区别 5、数组参数&#xff0c;指针参数 5.1数组参数定义 5.2指针参数定义 5.3一维数组传参 5.4二维数组传参 5.5一级指针传参 5.6二级指…

Matlab图像处理-彩色图像基础

光谱 在17世纪60年代&#xff0c;人们普遍认为白光是一种没有其他颜色的纯色光&#xff0c;而彩色光是有某种缘故发生变化的光。为了验证这个假设&#xff0c;牛顿让一束阳光通过一面三棱镜&#xff0c;光线在墙上被分解成了八种不同的颜色&#xff0c;即&#xff1a;红、橙、…

Unity SteamVR 开发教程:SteamVR Input 输入系统(2.x 以上版本)

文章目录 &#x1f4d5;前言&#x1f4d5;教程说明&#x1f4d5;导入 SteamVR 插件&#x1f4d5;SteamVR Input 窗口⭐action.json 文件⭐窗口面板⭐SteamVR_Input 目录 &#x1f4d5;SteamVR 动作的类型⭐Boolean⭐Single⭐Vector2⭐Vector3⭐Pose⭐Skeleton⭐Vibration &…

postgresql -数据库事务与并发控制

postgresql -数据库事务与并发控制 数据库事务事务控制语句并发与隔离数据库事务 事务控制语句 -- serial 自增 CREATE TABLE accounts(id serial PRIMARY KEY,user_name varchar(50),balance numeric

Windows11 OneDrive 安装后无法打开的解决办法

按 WinR &#xff0c;输入 gpedit.msc 在 本地组策略编辑器 中找到 计算机配置 > 管理模板> Windows 组件 > OneDrive&#xff0c;找到 禁止使用 OneDrive 进行文件存储 然后双击 禁止使用 OneDrive 进行文件存储&#xff0c;将中改为 已禁用&#xff0c;点击应用并…