SpringMVC之JSR303和拦截器

2023-09-12 21:15:56

目录

一.JSR 303

1.1.介绍

 1.2.为什么要使用JSR-303

 1.3.常用注解

 1.4. 快速入门

1.4.1.导入依赖

1.4.2.配置校验规则

1.4.3.编写方法校验

1.4.4.测试

二.拦截器

2.1.什么是拦截器 ?

 2.2.拦截器与过滤器的区别  

 2.3.拦截器的应用场景

2.4. 基础使用

 2.5.用户登录权限控制

最后实战SpringMVC之JSR303和拦截器就到这里,祝大家在敲代码的路上一路通畅!

感谢大家的观看 !


一.JSR 303

1.1.介绍

JSR 303是Java规范请求(Java Specification Request)的一个编号,它定义了一种用于在JavaBean上进行数据校验的标准方法。该规范被称为Bean验证,它提供了一种声明性的方式来验证JavaBean的属性值是否符合要求。

JSR 303规范定义了一组注解,开发人员可以将这些注解应用于JavaBean的属性上,以指定不同的约束条件。例如,@NotNull注解用于标记属性不能为空,@Min和@Max注解用于限制属性的最小和最大值,@Size注解用于限制属性的长度等等。

通过使用JSR 303规范,开发人员可以在编译时和运行时对JavaBean的属性进行自动验证,这样可以提高代码的健壮性和可维护性。开发人员可以根据具体的业务需求定义自己的约束条件,并通过编写自定义的验证器来实现。

需要注意的是,JSR 303只提供了基本的验证功能,例如数据类型、非空、长度等方面的验证。对于复杂的逻辑验证,开发人员可能需要自己编写额外的代码来实现。另外,JSR 303规范在Java EE 6及以上版本中被广泛支持,也可以在其他Java环境中使用。

 1.2.为什么要使用JSR-303

使用JSR-303的主要目的是简化和统一数据验证的过程。下面是使用JSR-303的几个重要理由:

  • 易于使用和维护:通过使用注解来定义约束条件,开发人员可以在JavaBean上直接标记验证规则,而不需要编写大量的验证代码。这样可以减少代码的冗余和维护成本。
  • 代码可读性和可重用性:通过将验证规则集中在JavaBean上,可以使代码更易读、清晰和可重用。其他开发人员可以通过查看注解来快速理解属性的验证要求。
  • 提高开发效率:JSR-303框架提供了内置的验证器和约束条件,开发人员可以直接使用这些验证器,无需自己编写验证逻辑。这样可以节省开发时间和精力。
  • 与框架和工具的集成:许多Java框架和工具已经集成了JSR-303规范,例如Spring框架、Hibernate、JAX-RS等。通过使用JSR-303,开发人员可以更轻松地将验证功能与这些框架和工具集成。

 1.3.常用注解

注解说明
@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

 注@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 = "职业编号不能为空")
//    @Size(max = 100,min = 10,message = "大小必须在10至100之间")
    protected Integer did;
    @NotBlank(message = "职业人名不能为空")
    protected String dname;
    @NotBlank(message = "职业工作不能为空")
    protected String dwork;

    private String dtp;

1.4.3.编写方法校验

在MusicController类中添加以下方法:

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

1.4.4.测试

工作台输出结果 :

二.拦截器

2.1.什么是拦截器 ?

拦截器(Interceptor)是在Web开发中常用的一种技术,它可以在请求到达目标处理程序之前或之后对请求和响应进行拦截和处理。拦截器通常用于实现一些公共的、横切关注点的功能,例如权限验证、日志记录、性能监控等。

拦截器工作在请求的处理链上,类似于一个过滤器,可以在请求到达控制器之前或之后执行自定义的逻辑。当一个请求到达时,拦截器可以对请求参数进行验证、对请求进行记录或修改、对请求进行权限检查等操作。在请求处理完毕后,拦截器还可以对响应进行处理,例如添加响应头、对响应结果进行包装、处理异常等。

拦截器的使用可以有效地将一些横切关注点从业务逻辑中分离出来,提高代码的可重用性和可维护性。拦截器还可以帮助开发人员实现一些通用的功能,例如记录日志、处理异常、权限验证等,减少编写重复代码的工作量。

在Web开发框架中,例如Spring MVC,拦截器通常通过实现接口或继承相关类来定义,并通过配置文件或注解的方式进行注册和使用。拦截器可以在请求的特定阶段进行调用,例如在请求处理器执行之前或之后,可以对请求进行修改或验证。

 拦截器工作原理  

 2.2.拦截器与过滤器的区别  

过滤器和拦截器的区别:

  •   拦截器是基于java的反射机制的,而过滤器是基于函数回调。
  •   拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
  •   拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
  •   拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
  •   在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
  •   拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
  •   拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
  •   拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
  •   拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

拦截器可以获取ioc中的service bean实现业务逻辑,拦截器可以获取ioc中的service bean实现业务逻辑,拦截器可以获取ioc中的service bean实现业务逻辑,

 2.3.拦截器的应用场景

  • 日志记录:拦截器可以用于记录请求的相关信息,如请求的URL、请求参数、请求的处理时间等。通过拦截器记录日志,可以方便后续的系统日志记录和分析,以及对请求的追踪和排查问题。
  • 权限验证:拦截器可以用于对用户进行权限验证,判断用户是否具有访问特定资源的权限。例如,在用户访问某个需要登录的页面之前,拦截器可以检查用户是否已登录,并根据用户的角色判断是否有权限访问该页面。
  • 请求预处理:拦截器可以用于对请求进行预处理,如字符编码转换、请求参数解析、请求数据的封装等。通过拦截器进行预处理,可以减轻目标处理器的负担,提高请求的处理效率和系统的稳定性。
  • 性能监控:拦截器可以用于监控请求的处理时间,用于系统的性能分析和优化。例如,拦截器可以记录请求的处理时间,并根据时间阈值进行性能告警或者对慢请求进行分析和优化。

总之,拦截器可以应用于多个场景,包括权限验证、日志记录、参数校验、请求预处理、请求后处理、异常处理和性能监控等。通过拦截器,开发人员可以对请求进行统一的处理,提高代码的复用性和可维护性,同时实现系统的安全性、稳定性和性能优化。

2.4. 基础使用

 创建一个名为 Interceptor 的包,存放创建自定义拦截器:

创建一个创建自定义拦截器,名为 : OneInterceptor,代码如下:

package com.junlinyi.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.junlinyi.interceptor.LoginInterceptor"></bean>
    </mvc:interceptors>

 

 演示测试结果为: 

 拦截器链(同时配置多个拦截器,可以进行区别拦截)

在 Interceptor 的包里,创建一个拦截器 TwoInterceptor:

package com.junlinyi.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 的配置文件中,配置自定义拦截器链:

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

 演示测试结果为: 

 2.5.用户登录权限控制

创建一个名为 : LoginInterceptor 的拦截器:

package com.junlinyi.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 uname = (String) request.getSession().getAttribute("uname");
        if (uname == null || "".equals(uname)){
            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 {

    }
}

 创建一个名为 : LoginController 的控制器:

package com.junlinyi.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * @author 君临沂
 * @site www.junlinyi.jly
 * @company 君氏集团
 * @create 2023-09-12-19:28
 */

@Controller
public class LoginController {
    @RequestMapping("/login")
    public String login(HttpServletRequest req){
        String uname = req.getParameter("uname");
        HttpSession session = req.getSession();
        if ("gb".equals(uname)){
            session.setAttribute("uname",uname);
        }
        return "redirect:/work/list";
    }

    @RequestMapping("/logout")
    public String logout(HttpServletRequest req){
        req.getSession().invalidate();
        return "redirect:/work/list";
    }
}

 创建一个 login.jsp 的显示页面,进行测试效果:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录界面</title>
</head>
<body>
<form action="/login" method="post">
    用户名:<input name="uname" >
    <input type="submit">
</form>
</body>
</html>

 在名为 spring-mvc.xml 的配置文件中,配置自定义拦截器,配置登入的用户。

 测试效果:

最后实战SpringMVC之JSR303和拦截器就到这里,祝大家在敲代码的路上一路通畅!

感谢大家的观看 !

更多推荐

Redis RedLock算法和底层源码分析

Redlock红锁算法官网地址:DistributedLockswithRedis|Redis为什么要使用RedLock?解释:线程1首先获取锁成功,将键值对写入redis的master节点,在redis将该键值对同步到slave节点之前,master发生了故障;redis触发故障转移,其中一个slave升级为新的ma

Java开发面试--Redis专区

1、什么是Redis?它的主要特点是什么?答:Redis是一个开源的、基于内存的高性能键值对存储系统。它主要用于缓存、数据存储和消息队列等场景。高性能:Redis将数据存储在内存中,并采用单线程的方式处理请求,使得其读写速度非常快,能够达到10万+的读写操作每秒。数据结构丰富:Redis支持多种数据结构,包括字符串、列

ChunJun(OldNameIsFlinkX)

序言ChunJun主要是基于Flink实时计算框架,封装了不同数据源之间的数据导入与导出功能.我们只需要按照ChunJun的要求提供原始与目标数据源的相关信息给Chunjun,然后它会帮我们生成能运行与Flink上的算子任务执行,这样就避免了我们自己去根据不同的数据源重新编辑读入与读出的方案了cuiyaonan2000

Vue.js模板语法[下](事件处理,表单综合案例,自定义组件)---详细讲解

一,事件处理1.`.stop`:阻止事件冒泡。使用该修饰符可以阻止事件向父元素传播2.`.prevent`:阻止默认事件。使用该修饰符可以阻止事件的默认行为。3.`.capture`:使用事件捕获模式。默认情况下,事件是在冒泡阶段处理的,使用该修饰符可以改为在捕获阶段处理。4.`.self`:只在事件触发的元素自身上触

数据交易是什么?看这篇文章

数据已经成为第五类生产要素,数据交易可以有效发挥数据价值,释放数据要素潜力。但数据又具有高敏感性的特点,承载着复杂的权利内容和权利主体,故数据交易需要限定在特定范围内,并遵循特有的规则规范。哪些数据可以进行交易,如何进行交易,数据交易要注意什么问题,这些都是数据交易的基础性问题。本文将以贵阳、北京、上海这三所国内代表性

对权限的理解和使用

目录一:用户权限:★su命令★sudo命令二:文件权限★文件的类型+权限★文件夹的权限的使用▲文件夹的可读权限:▲文件夹的可写权限:▲文件夹的可执行权限:★权限的修改操作▲chmod命令★对于文件的用户分组的修改▲chown命令▲chgrp命令★权限掩码以及umask指令★粘滞位的使用场景及使用方法在Linux当中我们

一文教你如何设计出优秀的测试用例(文档+视频)

这篇文章我们主要聊一下软件测试工程师最通用的也是最根本的技能,测试用例的设计能力。测试用例测试用例是通过使用在测试计划中确定的测试技术,对于已确定的测试条件进行逐步推敲,精炼而设计出来的重点说明如何具体操作产生何种结果的文档。通俗的话就是要把想要测试的动作变成在什么情况下,做什么动作,用什么数据方式去做,最后想得到什么

软件测试之功能测试详解

一、功能测试概述1)功能测试就是对产品的各功能进行验证,根据功能测试用例,逐项测试,检查产品是否达到用户要求的功能。2)功能测试,根据产品特性、操作描述和用户方案,测试一个产品的特性和可操作行为以确定它们满足设计需求。本地化软件的功能测试,用于验证应用程序或网站对目标用户能正确工作。使用适当的平台、浏览器和测试脚本,以

数据研发“新人”如何快速落地?

作者:肖迪(墨诩)一、前言这个季度主推安全月构筑&夯实稳定性底盘,就组织了组里的同学对核心业务链路进行了稳定性的摸排。在摸排过程中,不断有个声音在问你摸排出来的问题就是全部问题么?你加的监控加全了么?你的技改方案考虑全了么?(这个声音主要来自左耳,因为我leader坐在我的左边,哈哈哈哈)所以我们一直在思考和对焦,如何

SpringMVC之JSON数据返回及异常处理机制

目录一.JSON数据的返回二.异常处理机制2.1异常处理方式一2.2异常处理方式二2.3异常处理方式三一.JSON数据的返回JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式,常用于Web应用程序和服务之间的数据传输。通过使用JSON,数据可以以一种结构化的方式进行组织和存储,并可以

图像处理领域之►边缘检测大合集◄【应该是全网仅有的了吧】

图像处理领域之►边缘检测‧大合集◄概述{\color{Brown}概述}概述数据集{\color{Purple}数据集}数据集实践{\color{Red}实践}实践深度学习方法{\color{Blue}深度学习方法}深度学习方法机器学习方法{\color{Blue}机器学习方法}机器学习方法基于传统方法{\color{

热文推荐