SpringMVC之JSR303和拦截器

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 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和拦截器就到这里,祝大家在敲代码的路上一路通畅!

感谢大家的观看 !

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
6月前
SpringMVC之拦截器和异常处理器
【1月更文挑战第20天】SpringMVC之拦截器和异常处理器
70 0
|
12月前
|
缓存 前端开发 Java
SpringMVC之JSR303和拦截器
SpringMVC之JSR303和拦截器
72 0
|
前端开发 Java 数据库连接
SpringMVC系列(五)之JSR303和拦截器
SpringMVC系列(五)之JSR303和拦截器
|
12月前
|
监控 前端开发 Java
SpringMVC之JSR303使用及拦截器使用(带你探索SpringMVC的新领域)
SpringMVC之JSR303使用及拦截器使用(带你探索SpringMVC的新领域)
74 0
|
6月前
|
前端开发 Java Apache
JAVAEE框架技术之6-springMVC拦截器和文件上传功能
JAVAEE框架技术之6-springMVC拦截器和文件上传功能
99 0
JAVAEE框架技术之6-springMVC拦截器和文件上传功能
|
6月前
SpringMVC拦截器的介绍,拦截器的基本实现,拦截器链配置
SpringMVC拦截器的介绍,拦截器的基本实现,拦截器链配置
50 2
|
12月前
|
缓存 前端开发 Java
【SpringMVC】JSR 303与拦截器注解使用
【SpringMVC】JSR 303与拦截器注解使用
70 0
|
6月前
|
前端开发 Java 应用服务中间件
SpringMvc拦截器和手写模拟SpringMvc工作流程源码详解
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分。 M: Model,模型层,指工程中的JavaBean,作用是处理数据。 JavaBean分为两类: 1.实体类Bean:专门存储业务数据的,如Student User等 2.业务处理Bean:指Service或Dao对象,专门用于处理业务逻辑和数据访问。
|
6月前
|
前端开发 JavaScript Java
Spring Boot中Spring MVC的基本配置讲解与实战(包括静态资源配置,拦截器配置,文件上传配置及实战 附源码)
Spring Boot中Spring MVC的基本配置讲解与实战(包括静态资源配置,拦截器配置,文件上传配置及实战 附源码)
208 1
|
6月前
|
存储 调度
SpringMVC 拦截器开发详解
SpringMVC 拦截器开发详解