• 【SpringMVC】JSR303与拦截器的使用


    一、JSR303

    1.1 JSR303是什么

    JSR 303是Java规范请求(Java Specification Request)的编号,它定义了Java Bean验证的标准规范。JSR 303的全称是Bean Validation,它提供了一种在Java应用程序中进行数据验证的机制。

    Bean Validation是一种基于注解的验证框架,它允许开发人员在Java Bean的属性上添加验证规则,以确保数据的合法性和完整性。通过使用Bean Validation,开发人员可以在数据输入阶段就捕获错误,避免后续可能出现的潜在问题。

    1.2 JSR 303的好处包括

    1. 简化验证逻辑:通过使用注解,开发人员可以在Java Bean的属性上直接添加验证规则,而不需要编写繁琐的验证代码。
    2. 统一验证规范:JSR303定义了一组常用的验证注解,使得不同的开发人员在验证过程中可以使用相同的规范,提高了代码的可读性和可维护性。
    3. 提高代码质量:通过在Java Bean中添加验证规则,可以在数据输入阶段就捕获错误,避免了后续可能出现的潜在问题。
    4. 可扩展性:JSR303提供了自定义注解的能力,开发人员可以根据自己的需求定义新的验证注解。

    1.3 常用注解

    1. @NotNull:用于验证属性值不能为null。
    2. @Size:用于验证字符串、集合或数组的大小是否在指定范围内。
    3. @Min:用于验证数字属性的最小值。
    4. @Max:用于验证数字属性的最大值。
    5. @Pattern:用于验证字符串属性是否符合指定的正则表达式。
    6. @Email:用于验证字符串属性是否符合电子邮件格式。
    7. @NotBlank:用于验证字符串属性是否非空且长度大于0。
    8. @NotEmpty:用于验证字符串、集合或数组属性是否非空。
    9. @Range:用于验证数字属性是否在指定范围内。
    10. @Valid:用于嵌套验证,验证关联对象。

    1.4 实例

    1.4.1 导入JSR303依赖

    
    <hibernate.validator.version>6.0.7.Finalhibernate.validator.version>
     
    
    <dependency>
        <groupId>org.hibernategroupId>
        <artifactId>hibernate-validatorartifactId>
        <version>${hibernate.validator.version}version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    1.4.2 规则配置

    package com.xqx.model;
     
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.hibernate.validator.constraints.Length;
     
    import javax.validation.constraints.NotBlank;
    import javax.validation.constraints.NotNull;
     
    @Data//相当于set get toString方法
    @AllArgsConstructor //有参构造器
    @NoArgsConstructor //无参构造器
    public class Book{
    
    		 @NotBlank(message = “书本信息不能为空!")
    		 private String bookName;
    
    		 @NotNull(message = “书本价格不能为空!")
    		 private Float bookPrice:
    		 
    		 private String bookType;
     
       
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    1.4.3 编写校验方法

      /**
         * 书本新增
         * 请求路径 SSM/book/editBook
         * @param book
         * @return
         */
        @RequestMapping("/addBook")
        public String addBook(@Validated Book book, BindingResult bindingResult){
            System.out.println("进入新增方法");
            //判断是否验证成功
            if(bindingResult.hasErrors()){
                System.out.println("验证失败");
                //验证失败
                return "book/addBook";
     
            }else {
                //验证成功
            bookService.insert(book);
            return "redirect:queryBookPage";
            }
        }
     
        /**
         *  @ModelAttribute: 所标记的方法为非请求处理方法,在所有请求方法之前被调用
         *  @odelAttribute 在所有的@RequestMapping的方法之前被调用!
         *
         *  作用:数据预加载
         *  特点:无返回值
         */
        @ModelAttribute
        public void init(Model model){
            System.out.println("非请求处理方法");
            //必须操作
            model.addAttribute("book",new Book());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    1.4.4 编写前端

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib prefix="fmt" uri="http://www.springframework.org/tags/form" %>
    <html>
    <head>
        <%@include file="/common/head.jsp"%>
        <title>Titletitle>
    head>
    <style>
           .cl{
               color: red;
           }
     
    style>
    <body>
    <h1>书本新增h1>
        <fmt:form modelAttribute="book"  action="${ctx}/book/addBook" method="post">
            <label>书本名称:label><input type="text" name="bookName"><fmt:errors cssClass="cl" path="*"/><br/>
            <label>书本价格:label><input type="text" name="bookPrice"><%--<fmt:errors cssClass="cl"  path="bookPrice"/>--%><br/>
            <label>书本类型:label>
            <select name="bookType">
                <option value="神话">神话option>
                <option value="教育">教育option>
                <option value="文学">文学option>
                <option value="玄幻">玄幻option>
            select>
     
            <br/>
            <input type="submit" value="添加">
        fmt:form>
     
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    二、拦截器

    2.1 拦截器是什么

    SpringMVC的处理器拦截器,类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。依赖于web框架,在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。

    2.2 拦截器与过滤器的区别

    拦截器(Interceptor)通常是指一种拦截和处理请求的组件或模块。它可以在请求到达目标之前或之后进行拦截,并对请求进行修改、记录或处理。拦截器通常用于实现横切关注点(cross-cutting concerns),如日志记录、安全认证、性能监控等。拦截器可以在应用程序的不同层级中使用,例如在网络层、业务逻辑层或数据访问层。

    过滤器(Filter)则是一种用于过滤和处理数据的组件或模块。它可以在数据流经过时对数据进行过滤、转换或处理。过滤器通常用于对数据进行预处理或后处理,以满足特定的需求或要求。常见的应用包括数据清洗、数据转换、数据压缩等。过滤器可以在不同的数据处理环节中使用,例如在输入输出流、数据库查询、图像处理等。

    2.3.应用场景

    • 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
    • 权限检查:如登录检测,进入处理器检测是否登录,如果没有直接返回到登录页面;
    • 性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
    • 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个Controller中的处理方法都需要的,我们就可以使用拦截器实现。

    2.4 快速入门

    创建拦截器

    package com.xqx.interceptor;
     
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
     
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
     
    /*
    1. 定义拦截器类,实现HandlerInterceptor接口
    2. 注意当前类必须受Spring容器控制
     */
    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...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    配置拦截器

    在spring-mvc.xml中配置:

        
        <mvc:interceptors>
            <bean class="com.xqx.interceptor.OneInterceptor">bean>
        mvc:interceptors>
    
    • 1
    • 2
    • 3
    • 4

    2.5.拦截器链

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

    在spring-mvc.xml中配置多个拦截器

        
        <mvc:interceptors>
                <mvc:interceptor>
                    
                    <mvc:mapping path="/**"/>
                    <bean class="com.xqx.interceptor.OneInterceptor"/>
                mvc:interceptor>
                <mvc:interceptor>
                    
                    <mvc:mapping path="/book/**"/>
                    <bean class="com.xqx.interceptor.TwoInterceptor"/>
                mvc:interceptor>
        mvc:interceptors>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    使用了拦截器链的效果
    在这里插入图片描述

    2.6 登录拦截权限案例

    2.6.1 LoginController.java

    package com.xqx.controller;
     
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
     
    import javax.servlet.http.HttpSession;
     
    @Controller
    public class LoginController {
     
        /**
         * 跳转到登录页面
         * @return
         */
        @RequestMapping("tologin")
        public String toLogin(){
            return "login";
        }
     
        /**
         * 登录方法
         * @param username 账号
         * @param password 密码
         * @return
         */
        @RequestMapping("/userLogin")
        public String userLogin(String username, String password, HttpSession session, Model model){
            if("admin".equals(username)|| password.equals("123")){
               session.setAttribute("username",username);
                //这里的"/"是跳转的@RequestMapping配置的值
                return "redirect:/";
            }
     
            model.addAttribute("msg","账号或者密码错误");
            return "login";
        }
     
     
        /**
         * 安全退出
         * @param session
         * @return
         */
        @RequestMapping("/userLogout")
        public String userLogout(HttpSession session){
            //清空session
            session.invalidate();
     
            return "redirect:tologin";
        }
     
     
     
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    2.6.2 配置拦截器

    <mvc:interceptors>
        <bean class="com.xqx.interceptor.LoginInterceptor">bean>
    mvc:interceptors>
    
    • 1
    • 2
    • 3

    2.6.3 创建拦截器

    package com.xqx.interceptor;
     
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
     
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
     
    public class LoginInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            //获取请求路径
            String url = request.getRequestURI();
            System.out.println(url);
            //判断是否是跳转登录页面的请求 放行
            if(url.indexOf("/tologin")>0)
                return true;
            //判断是否是用户登录 放行
            if(url.indexOf("/userLogin")>0)
                return true;
            //获取session
            HttpSession session = request.getSession();
            //获取session中的用户对象
            String username = (String) session.getAttribute("username");
            //判断session中的用户对象是否存在,存在放行,不存在跳转登录页面
            if(username!=null)
                return true;
            request.setAttribute("msg","您还没有登录,请登录!");
            request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);
            return false;
        }
     
        @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 {
     
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    2.6.4 测试

    账号密码错误的情况下
    在这里插入图片描述
    在未登录的情况下访问首页
    在这里插入图片描述

  • 相关阅读:
    CSPM是否可以申请职称?解答来了
    非关系型数据库-Redis
    Layui快速入门之第七节 表格
    【算法基础】栈和队列及常见变种与使用,双栈、动态栈、栈的迭代器,双端队列、优先队列、并发队列、延迟队列的使用
    奇舞周刊第 459 期 精读《web reflow》
    Element-ui源码解析(二):最简单的组件Button
    Vue 自定义指令绑定的处理函数中传递参数
    SpringBoot配置文件
    【设计模式】代理模式
    为什么配置Java环境后会出现SSL问题?
  • 原文地址:https://blog.csdn.net/TestXzing/article/details/132842948