SpringMVC之JSR303和拦截器

目录

前言        

一、JSR303数据校验

1.JSR303是什么

2.为什么要使用JSR303

3.常用注解

4.@Validated与@Valid区别

5.入门案例

1.导入依赖

2.配置校验规则

3.编写校验方法

4.编写前端页面

5.测试

二、拦截器(interceptor)

1.什么是拦截器

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

3.拦截器的应用场景及作用

4.快速入门

创建拦截器

配置拦截器

测试

5.拦截器工作原理

6.拦截器链

创建拦截器

配置拦截器

测试 

7.拦截器登录权限案例

创建拦截器

配置拦截器

编写controller层处理登录的方法

编写前端页面

测试


前言        

        当涉及到Web应用程序的开发时,数据校验和拦截器是非常重要的功能。在SpringMVC框架中,我们可以使用JSR303数据校验和拦截器来实现这些功能。本文将详细介绍JSR303数据校验和拦截器的使用方法和原理。

一、JSR303数据校验

1.JSR303是什么

JSR303是Java规范中定义的一套用于数据校验的标准,它提供了一种简单而强大的方式来验证数据的合法性。在Java Web开发中,我们经常需要对用户提交的数据进行校验,以确保数据的有效性和安全性。JSR303提供了一套注解,我们可以通过在实体类的字段上添加这些注解来实现数据校验。

2.为什么要使用JSR303

1. 代码简洁:使用JSR 303可以将数据校验的逻辑从业务代码中分离出来,使代码更加简洁和易于维护。我们只需要在实体类的字段上添加相应的注解,就可以定义校验规则,而不需要编写大量的校验代码。

2. 统一校验规则:通过使用JSR 303,我们可以定义一套统一的校验规则,这样可以确保所有的数据校验都遵循相同的规范。这对于多个模块或团队共同开发的项目尤为重要,可以避免各自实现不一致的校验逻辑。

3. 前后端校验一致:JSR 303支持在前端和后端都进行数据校验。前端可以使用JavaScript框架如jQuery Validation等进行校验,后端可以使用Java框架如SpringMVC等进行校验。这样可以确保前后端的校验规则一致,提高系统的安全性和用户体验。

4. 可扩展性:JSR 303提供了一套标准的校验注解,但也支持自定义注解和校验器。我们可以根据项目的需求,自定义一些特定的校验规则,以满足业务的特殊需求。

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

4.@Validated与@Valid区别

@Validated@Valid是Spring框架中用于数据校验的注解,它们的作用是对方法参数或方法返回值进行校验。尽管它们的功能相似,但在使用上有一些区别。

  1. 适用范围:

    • @Valid注解适用于方法参数和方法返回值的校验。
    • @Validated注解适用于方法参数的校验。
  2. 校验器的选择:

    • @Valid注解使用的是Java Bean Validation(JSR 380)规范定义的校验器,例如Hibernate Validator。
    • @Validated注解使用的是Spring框架自带的校验器,例如Spring Validator。
  3. 分组校验:

    • @Valid注解支持分组校验,可以根据不同的校验场景选择不同的校验规则。
    • @Validated注解不支持分组校验,只能使用默认的校验规则。
  4. 错误处理:

    • @Valid注解的校验错误会被封装成MethodArgumentNotValidExceptionConstraintViolationException异常,并由全局异常处理器进行处理。
    • @Validated注解的校验错误会被封装成BindExceptionConstraintViolationException异常,并由全局异常处理器进行处理。

5.入门案例

1.导入依赖

6.0.7.Final



    org.hibernate
    hibernate-validator
    ${hibernate.validator.version}
2.配置校验规则
package com.ctb.model;

import lombok.ToString;
import org.hibernate.validator.constraints.NotBlank;

import javax.validation.constraints.NotNull;

@ToString
public class User {
    @NotNull(message = "用户编号不能为空")
    private Integer id;
    @NotBlank(message = "用户名不能为空")
    private String uname;

    private String upic;

    public User(Integer id, String uname, String upic) {
        this.id = id;
        this.uname = uname;
        this.upic = upic;
    }

    public User() {
        super();
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUname() {
        return uname;
    }

    public void setUname(String uname) {
        this.uname = uname;
    }

    public String getUpic() {
        return upic;
    }

    public void setUpic(String upic) {
        this.upic = upic;
    }
}
3.编写校验方法
//    给数据添加服务端校验
    @RequestMapping("/valiAdd")
    public String valiAdd(@Validated User user, BindingResult result, HttpServletRequest req){
//        如果服务端验证不通过,有错误
        if(result.hasErrors()){
//            服务端验证了实体类的多个属性,多个属性都没有验证通过
            List fieldErrors = result.getFieldErrors();
            Map 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.userBiz.insertSelective(user);
            return "redirect:list";
        }
        return "user/edit";
    }
4.编写前端页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


编辑信息

用户编号: ${errorMap.id}
用户名称: ${errorMap.uname}
用户头像:
5.测试

SpringMVC之JSR303和拦截器_第1张图片

二、拦截器(interceptor)

1.什么是拦截器

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

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

什么是过滤器(Filter)

        依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等

  • 拦截器是基于Java的反射机制实现的,而过滤器是基于Servlet规范实现的。
  • 拦截器只能拦截SpringMVC的请求,而过滤器可以拦截所有的请求。
  • 拦截器可以访问控制器的方法和参数,而过滤器只能访问请求和响应对象。
  • 拦截器可以在请求处理前后进行处理,而过滤器只能在请求处理前进行处理。

3.拦截器的应用场景及作用

  • 权限验证:拦截器可以检查用户是否具有访问某个资源的权限。
  • 日志记录:拦截器可以记录请求的详细信息,例如请求路径、请求参数等。
  • 性能监控:拦截器可以统计请求的处理时间,用于性能监控和优化。
  • 异常处理:拦截器可以捕获控制器处理过程中的异常,并进行相应的处理。

拦截器的作用是在请求到达控制器之前进行预处理,例如验证用户权限、记录日志等;在控制器处理完请求后进行后处理,例如记录响应日志、处理异常等。

4.快速入门

  • 创建拦截器

首先,创建一个实现HandlerInterceptor接口的拦截器类。该接口定义了三个方法,分别是preHandle、postHandle和afterCompletion,用于在请求处理前、请求处理后以及请求完成后进行拦截和处理。

package com.ctb.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...");
    }
}
  • 配置拦截器

在SpringMVC的配置文件中,配置拦截器的Bean,并指定拦截的路径。


    
        
    
  • 测试

在运行测试时会发现它们的运行顺序为

preHandle --> postHandle --> afterCompletion

SpringMVC之JSR303和拦截器_第2张图片

 注意:拦截器会根据preHandle()方法返回值进行拦截判断,返回了一个true值。这个返回值表示该拦截器已经处理了当前的请求,并且可以继续向下传递请求。如果返回false,则表示该拦截器不处理当前请求,请求将被终止。 

5.拦截器工作原理

SpringMVC之JSR303和拦截器_第3张图片

  • preHandle:用于对拦截到的请求进行预处理,方法接收布尔(true,false)类型的返回值,返回true:放行,false:不放行。

    执行时机:在处理器方法执行前执行

    方法参数

    参数 说明
    request 请求对象
    response 响应对象
    handler 拦截到的方法处理
  • postHandle:用于对拦截到的请求进行后处理,可以在方法中对模型数据和视图进行修改

    执行时机:在处理器的方法执行后,视图渲染之前

    方法参数

    参数 说明
    request 请求对象
    response 响应对象
    handler 拦截到的处理器方法
    ModelAndView 处理器方法返回的模型和视图对象,可以在方法中修改模型和视图
  • afterCompletion:用于在整个流程完成之后进行最后的处理,如果请求流程中有异常,可以在方法中获取对象

    执行时机:视图渲染完成后(整个流程结束之后)

    方法参数

    参数 说明
    request 请求参数
    response 响应对象
    handler 拦截到的处理器方法
    ex 异常对象
     

6.拦截器链

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

  • 创建拦截器
package com.ctb.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...");
    }
}
  • 配置拦截器

    
        
        
            
            
        
        
            
            
        
    
  • 测试 

SpringMVC之JSR303和拦截器_第4张图片

7.拦截器登录权限案例

  • 创建拦截器
package com.ctb.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 {

    }
}
  • 配置拦截器

    
        
    
  • 编写controller层处理登录的方法
package com.ctb.controller;

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

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

/**
 * @author 彪
 * @remark
 * @create  2023
 */
@Controller
public class LoginController {
    @RequestMapping("/login")
    public String login(HttpServletRequest req){
        String uname = req.getParameter("uname");
        HttpSession session = req.getSession();
        if ("ctb".equals(uname)){
            session.setAttribute("uname",uname);
        }
        return "redirect:/user/list";
    }

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

  • 编写前端页面
<%--
  Created by IntelliJ IDEA.
  User: 86155
  Date: 2023/9/13
  Time: 6:05
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


用户登录

用户:
  • 测试

登录

SpringMVC之JSR303和拦截器_第5张图片

退出 

SpringMVC之JSR303和拦截器_第6张图片

你可能感兴趣的:(SpringMVC,java,前端,开发语言,spring,mybatis,maven,intellij-idea)