SpringMVC之JSR303和拦截器

目录

一、JSR303

[1.1 什么是JSR303](#1.1 什么是JSR303)

[1.2 为什么要使用JSR303](#1.2 为什么要使用JSR303)

[1.3 常用注解](#1.3 常用注解)

[1.4 快速入门](#1.4 快速入门)

[1.4.1 导入依赖](#1.4.1 导入依赖)

[1.4.2 配置校验规则](#1.4.2 配置校验规则)

[1.4.3 入门案例](#1.4.3 入门案例)

二、拦截器

[2.1 什么是拦截器](#2.1 什么是拦截器)

[2.1.1 定义](#2.1.1 定义)

[2.1.2 作用领域](#2.1.2 作用领域)

[2.2 过滤器](#2.2 过滤器)

[2.2.1 定义](#2.2.1 定义)

[2.2.2 作用领域](#2.2.2 作用领域)

[2.3 拦截器与过滤器的区别](#2.3 拦截器与过滤器的区别)

[2.4 应用场景](#2.4 应用场景)

[2.5 快速入门](#2.5 快速入门)

[2.5.1 入门案例](#2.5.1 入门案例)

[2.5.2 拦截器工作原理](#2.5.2 拦截器工作原理)

[2.6 拦截器链](#2.6 拦截器链)

[2.7 用户登录权限控制](#2.7 用户登录权限控制)


一、JSR303

1.1 什么是JSR303

JSR303是Java规范请求(Java Specification Request)的编号,它定义了Java Bean验证的标准。Java Bean验证是一种验证框架,可以验证Java Bean中的属性,以确保它们符合特定的规则和约束。该框架在Java EE 6中得到了官方支持,并在javax.validation包中实现。JSR303规范定义了验证注释,这些注释可以应用于Java Bean的属性上,以指示验证规则。这些验证规则可以检查属性是否为空、是否符合正则表达式、是否在指定范围内等等。通过使用JSR303,我们可以确保Java Bean的属性始终符合预期,并在出现错误时及时捕获并处理这些错误。

JSR303的定义:

JSR303是一种Java平台标准,也称为Bean Validation,用于验证JavaBean和其他Java对象的声明约束。JSR303使用注释标记属性的限制,并提供了一个验证引擎,该引擎可以在运行时执行验证以确保对象的有效性。它提供了一种轻松的方式来验证表单数据和其他用户输入,防止不良数据进入应用程序。JSR303旨在提供一致的验证机制,使Java应用程序更加健壮和可维护。

1.2 为什么要使用JSR303

JSR303是Java Validation API的规范,它提供了一种简单易用的验证框架,帮助我们在实体类属性上进行验证,对于确保数据的正确性和完整性非常有用。 使用JSR303可以带来以下好处:

  1. 易于维护和扩展:将验证规则注解到属性上,代码易于维护和扩展,避免了繁琐的手工验证。

  2. 提高代码可读性:验证规则注解到属性上,代码可读性大大提高。

  3. 减少重复代码:使用JSR303可以减少编写检验代码的重复工作,提高生产效率。

  4. 提高系统健壮性:通过JSR303验证规则的定义,可以确保数据的正确性和完整性,提高系统健壮性和稳定性。

1.3 常用注解

JSR303是Java中的Bean Validation规范,其中定义了许多注解用于对JavaBean中的属性进行验证。以下是常用的JSR303注解及其解释:

  1. @NotNull:验证字段不为null。

  2. @NotBlank:验证字段不为空,即长度大于0,去掉空格后长度大于0。

  3. @NotEmpty:验证字段不为空,即长度大于0。

  4. @Min:验证数字字段的最小值。

  5. @Max:验证数字字段的最大值。

  6. @Size:验证字段的大小范围。

  7. @DecimalMin:验证十进制数字段的最小值。

  8. @DecimalMax:验证十进制数字段的最大值。

  9. @Pattern:验证字段匹配正则表达式。

  10. @Email:验证字段为Email格式。

  11. @Length:验证字段的长度。

  12. @Range:验证字段的值在范围内。

  13. @Valid:验证嵌套对象。

  14. @AssertTrue:验证字段为true。

  15. @AssertFalse:验证字段为false。

  16. @Past:验证日期字段在当前时间之前。

  17. @Future:验证日期字段在当前时间之后。

以上是常用的JSR303注解及其解释,开发者可以根据实际情况选择需要的注解。

注**@Validated与@Valid区别** ::

@Validated:

  • Spring提供的

  • 支持分组校验

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

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

@Valid:

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

  • 不支持分组校验

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

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

1.4 快速入门

1.4.1 导入依赖

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>

1.4.2 配置校验规则

校验属性是否为空:

java 复制代码
 @NotNull(message = "歌曲编号不能为空")
    private Integer mid;
    @NotBlank(message = "歌曲名称不能为空")
    private String mname;
    @NotBlank(message = "歌曲专辑不能为空")
    private String mtype;
    @NotBlank(message = "歌曲歌词不能为空")
    private String minfo;
    @NotBlank(message = "歌曲图片不能为空")
    private String mpic = "暂无图片";

1.4.3 入门案例

在MusicController类中添加以下方法:

java 复制代码
 //    给数据添加服务端校验
    @RequestMapping("/valiAdd")
    public String valiAdd(@Validated Music music, 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.musicBiz.insertSelective(music);
            return "redirect:list";
        }
        return "mic/edit";
    }

在服务端中进行校验,校验的模型的属性中出现错误,则将错误信息的属性进行遍历添加到map集合中并保存起来回显到前端,需要注意的是,注解@validated保存的是校验时的参数,最终校验的结果保存在BindingResult中.

1.4.4 结果测试

在没有进行后端效验前应该会报空指针异常。

但是在进行后端效验之后,就会将我们的错误信息反馈到前端的展示界面,如下:

控制台效果:

二、Java三大器之拦截器

2.1 什么是拦截器

2.1.1 定义

在Java编程中,拦截器(Interceptor)是一种常见的机制,它可以拦截方法的调用或者HTTP请求的处理过程,并在处理前后执行一些特定的操作或者逻辑。拦截器通常用于实现各种不同的功能,如权限控制、日志记录、事务管理等。

2.1.2 作用领域

在Java Web开发中,拦截器常用于拦截HTTP请求并进行处理,例如进行身份验证、拦截非法的请求、记录日志等。在Spring框架中,拦截器是一个非常重要的组件,可以通过实现HandlerInterceptor接口来定义拦截器,然后在配置文件中配置拦截器的拦截规则和执行顺序。在Struts2、Spring MVC等Web框架中也都有拦截器的支持。

2.2 Java三大器之过滤器

2.2.1 定义

Java中的过滤器(Filter)是一种用于拦截HTTP请求和响应的组件,它在请求到达Servlet之前拦截并验证HTTP请求,或在Servlet响应到达客户端前对响应进行处理。在Java Web应用中,过滤器是一个可配置的组件,它需要在web.xml文件中注册并配置相应的属性才能生效。可以通过编写实现javax.servlet.Filter接口的Java类来定义过滤器的功能。

2.2.2 作用领域

过滤器通常用于实现一些通用的处理逻辑,比如认证、日志记录、统计信息等,以提高代码复用性和可维护性。过滤器还可以用于跨站点脚本攻击(XSS)和跨站点请求伪造(CSRF)等安全机制的实现。

2.3 拦截器与过滤器的区别

图解如下:

拦截器和过滤器都是在Java Web开发中对请求进行拦截处理的一种工具,但是它们有以下区别:

  1. 执行顺序: 过滤器是在Servlet容器调用servlet之前或之后执行的,而拦截器是在servlet处理请求之前或之后执行的。

  2. 作用范围: 过滤器作用于所有的请求和响应,包括静态资源,而拦截器只拦截配置的路径及其子路径的请求。

  3. 功能范围: 过滤器可以在过滤器链中做一些额外的功能,如字符编码、请求转发和重定向等,而拦截器可以更好地控制业务流程,如权限控制、日志记录等。

  4. API不同: 过滤器是使用Servlet API实现的,而拦截器是使用Spring MVC框架自身的接口实现的。

总的来说,过滤器更加通用,可以实现一些基本的请求过滤和处理操作,而拦截器则更加灵活,可以根据业务需求实现更加复杂的操作。在实际应用中,需要根据具体的需求选择使用过滤器还是拦截器。

2.4 应用场景

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

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

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

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

2.5 拦截器工作原理

2.6 用户登录权限控制

基本拦截器配置(在Java目录下新建一个interceptor包,创建拦截器类):

OneInterceptor:

java 复制代码
package com.Kissship.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...");
    }
}

TwoInterceptor:

java 复制代码
package com.Kissship.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中配置多拦截器,添加代码如下:

XML 复制代码
 <!--&lt;!&ndash;    用户权限的请求拦截&ndash;&gt;-->
    <mvc:interceptors>
        <bean class="com.Kissship.interceptor.LoginInterceptor"></bean>
    </mvc:interceptors>

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

然后接下来创建一个名为LoginInterceptor的拦截器,如下:

java 复制代码
package com.Kissship.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 mname = (String) request.getSession().getAttribute("mname");
        if (mname == null || "".equals(mname)){
            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 {

    }
}

接着创建一个新的jsp页面用来充当登录界面进行效果测试,login.jsp代码如下:

html 复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户登入</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/login" method="post" enctype="multipart/form-data">
    <label>用户名称:</label><br/>
    <input type="text" name="mname"/><br/>
    <input type="submit" value="登入"/>
</form>
</body>
</html>

最后进行测试,效果如下:


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

感谢大家的观看 !

相关推荐
程序员大金几秒前
基于SpringBoot+Vue+MySQL的在线学习交流平台
java·vue.js·spring boot·后端·学习·mysql·intellij-idea
shinelord明1 分钟前
【Python】Python知识总结浅析
开发语言·人工智能·python
吹老师个人app编程教学6 分钟前
阿里巴巴_java开发规范手册详解
java·开发语言
天上掉下来个程小白6 分钟前
Stream流的终结方法(一)
java·windows
初阳78525 分钟前
【Qt】控件概述(4)—— 输出类控件
开发语言·qt·命令模式
天上掉下来个程小白28 分钟前
请求响应-08.响应-案例
java·服务器·前端·springboot
大白_dev28 分钟前
数据校验的总结
java·开发语言
雷神乐乐32 分钟前
Python常用函数
开发语言·python
失落的香蕉35 分钟前
Java第二阶段---10方法带参---第三节 面向对象和面向过程的区别
java·开发语言
安冬的码畜日常44 分钟前
【玩转 JS 函数式编程_008】3.1.2 JavaScript 函数式编程筑基之:箭头函数——一种更流行的写法
开发语言·javascript·ecmascript·es6·this·箭头函数