Java高级 | 【实验七】Springboot 过滤器和拦截器

发布于:2025-06-08 ⋅ 阅读:(15) ⋅ 点赞:(0)

隶属文章:Java高级 | (二十二)Java常用类库-CSDN博客

系列文章:Java高级 | 【实验一】Springboot安装及测试 |最新-CSDN博客

                  Java高级 | 【实验二】Springboot 控制器类+相关注解知识-CSDN博客

                  Java高级 | 【实验三】Springboot 静态资源访问-CSDN博客

                  Java高级 | 【实验四】Springboot 获取前端数据与返回Json数据-CSDN博客

                  Java高级 | 【实验五】Spring boot+mybatis操作数据库-CSDN博客

                  Java高级 | 【实验六】Springboot文件上传和下载-CSDN博客

目录

一、【过滤器】Filter

1.1 过滤器的功能

1.2 过滤器的工作原理

二、过滤器实验

2.1 实验项目结构

2.2 源码

(1)CorsFilter类

(2)FilterConfig类

(3)TimingFilter类

(4)TestController控制器类

2.3测试

(1)postman中测试结果

(2)Idea控制台输出的结果

三、【拦截器】interceptor

3.1 Interceptor使用场景

3.2 实现

3.3 工作/运行流程

四、 拦截器实验

4.1 新建工程

4.2 编写代码

(1)实体类

(2)拦截器类

(3)配置拦截器类

(4)编写控制器类

(5)创建前端页面

(6)修改主类

4.3 测试

一、【过滤器】Filter

       过滤器是对数据进行过滤,预处理过程,当我们访问网站时,有时候会发布一些敏感信息,发完以后有的会用*替代,还有就是登陆权限控制等,一个资源,没有经过授权,肯定是不能让用户随便访问的,这个时候,也可以用到过滤器。

1.1 过滤器的功能

还有很多,例如实现URL级别的权限控制、压缩响应信息、编码格式等等。拦截掉我们不需要的接口请求,修改请求(request)和响应(response)内容,完成CORS跨域请求等等。

1.2 过滤器的工作原理

二、过滤器实验

2.1 实验项目结构

      Myfilter包中定义了两个过滤器类和一个过滤器配置类:

  • CorsFilter跨域处理
  • FilterConfig:配置两个过滤器
  • TimingFilter:记录请求时间

2.2 源码

(1)CorsFilter类

package myfilter;

import jakarta.servlet.*;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.core.annotation.Order;

import java.io.IOException;
@WebFilter
public class CorsFilter implements Filter {
    // 初始化方法(Filter 容器启动时调用一次)
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("CorsFilter 初始化完成");
    }

    // 核心过滤方法(每个请求触发一次)
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.setHeader("Access-Control-Allow-Origin", "*");
        httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");

        System.out.println("CorsFilter 前置处理");
        chain.doFilter(request, response); // 继续后续处理
        System.out.println("CorsFilter 后置处理");
    }
    // 销毁方法(应用关闭时调用一次)
    @Override
    public void destroy() {
        System.out.println("CorsFilter 销毁");
    }
}

(2)FilterConfig

package myfilter;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
    // 注册 TimingFilter(顺序1)
    @Bean
    public FilterRegistrationBean<TimingFilter> timingFilterRegistration() {
        FilterRegistrationBean<TimingFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new TimingFilter());
        registration.addUrlPatterns("/*"); // 拦截所有路径
        registration.setOrder(1); // 优先级最高(数值越小优先级越高)
        return registration;
    }

    // 注册 CorsFilter(顺序2)
    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilterRegistration() {
        FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new CorsFilter());
        registration.addUrlPatterns("/*");
        registration.setOrder(2); // 优先级次之
        return registration;
    }
}

(3)TimingFilter类

package myfilter;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter // 可选注解(需配合 @ServletComponentScan)
public class TimingFilter implements Filter {
    private long startTime; // 记录请求开始时间
    // 初始化方法(Filter 容器启动时调用一次)
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("TimingFilter 初始化完成");
        // 可读取 Filter 配置参数(如 filterConfig.getInitParameter("key"))
    }
    // 核心过滤方法(每个请求触发一次)
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        startTime = System.currentTimeMillis();
        System.out.println("TimingFilter 前置处理开始");

        // 继续 Filter 链或 Controller
        chain.doFilter(request, response);

        long endTime = System.currentTimeMillis();
        System.out.println("TimingFilter 后置处理,总耗时:" + (endTime - startTime) + "ms");
    }
    // 销毁方法(应用关闭时调用一次)
    @Override
    public void destroy() {
        System.out.println("TimingFilter 销毁");
    }
}

(4)TestController控制器

package controller;


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
    @GetMapping("/test")
    public String test() {
        System.out.println("Controller 方法执行");
        return "Hello from Controller!";
    }
}

(5)修改MyfilterApplication主类

package com.example.myfilter;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = {"controller"})
@ComponentScan(basePackages = {"myfilter"})
public class MyfilterApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyfilterApplication.class, args);
    }
}

2.3测试

(1)postman中测试结果

(2)Idea控制台输出的结果



拦截器】interceptor

       拦截器(Interceptor)同 Filter 过滤器一样,它俩都是面向切面编程——AOP 的具体实现(AOP切面编程只是一种编程思想而已)。

  • 使用 Interceptor 来执行某些任务,例如在 Controller 处理请求之前编写日志,添加或更新配置等等
  • 在 Spring中,当请求发送到Controll时,在被Controller处理之前,它必须经过 Interceptors(0或多个)。

3.1 Interceptor使用场景

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

权限检查:如登录检测,进入处理器检测是否登录;

性能监控:通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间。(反向代理,如 Apache 也可以自动记录)

通用行为:读取 Cookie、session、header等 得到用户信息并将用户对象放入请求,从而方便后续流程使用。 

3.2 实现

通常用户可以自定义拦截器。

自定义 Interceptor 必须实现 org.springframework.web.servlet.HandlerInterceptor接口或继承 org.springframework.web.servlet.handler.HandlerInterceptorAdapter类,并且需要重写下面下面 3 个方法:

3.3 工作/运行流程

1、拦截器执行顺序是按照Spring配置文件中定义的顺序而定的。

2、会先按照顺序执行所有拦截器的preHandle方法,一直遇到return false为止,比如第二个preHandle方法是return false,则第三个以及以后所有拦截器都不会执行。若都是return true,则按顺序加载完preHandle方法。

3、然后执行主方法(自己的controller接口),若中间抛出异常,则跟return false效果一致,不会继续执行postHandle,只会倒序执行afterCompletion方法。

4、在主方法执行完业务逻辑(页面还未渲染数据)时,按倒序执行postHandle方法。若第三个拦截器的preHandle方法return false,则会执行第二个和第一个的postHandle方法和afterCompletion(postHandle都执行完才会执行这个,也就是页面渲染完数据后,执行after进行清理工作)方法。(postHandle和afterCompletion都是倒序执行)。

四、 拦截器实验

4.1 新建工程

工程名称为“test_interceptor”,创建工程的时候勾选Lombok、Spring Web、Thymeleaf。

工程创建完毕后在java包中创建bean、config、controller、interceptor等四个包。

本实验完整的工程图如下图所示:

4.2 编写代码

(1)实体类

在bean包中创建User类,其代码如下:

package bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {

    private String userName;
    private String password;
}

(2)拦截器类

在interceptor包中创建一个名为“LoginInterceptor”类,该类实现了HandlerInterceptor接口,说明该类是一个拦截器类。其代码如下:

package interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    // 目标方法执行之前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 拦截请求输出
        String requestURI = request.getRequestURI();
        log.info("拦截了请求{}", requestURI);
        // 登录检查逻辑,是否登录,登录成功以后放行资源,未登录则拦截资源
        HttpSession session = request.getSession();
        Object loginUser = session.getAttribute("loginUser");
        if (loginUser != null) {
            // 登录成功放行资源
            return true;
        } else {
            // 提示错误信息
            request.setAttribute("msg", "请先登录!");
            // 请求转发
            request.getRequestDispatcher("/").forward(request, response);
            // 未登录拦截资源
            return false;
        }
    }
    // 目标方法执行完毕
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle执行{}",modelAndView);
    }
    // 页面渲染以后
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion执行异常{}",ex);
    }
}

(3)配置拦截器类

该类主要功能是拦截哪些请求和不拦截哪些请求。

在config包中创建一个名为“MyWebConfig”的类,该类实现了WebMvcConfigurer接口。其代码如下:

package config;

import interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
// 自定义springboot配置类
@Configuration
public class MyWebConfig implements WebMvcConfigurer {
    // 添加注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**") // 拦截所有请求
                .excludePathPatterns("/","/login","/mylogin"); // 放行请求
        //平常可以写这样             // .excludePathPatterns("/","/login","/css/**","/js/**","/fonts/**","/images/**");
    }
}

(4)编写控制器类

在controller包中编写一个名为“LoginController”的类,该类的代码如下啊:

package controller;

import bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class LoginController {
    @PostMapping("/mylogin")
    public String login(User user, Model model){
        System.out.println(user);
        if ("robin".equals(user.getUserName())&&"123456".equals(user.getPassword())){
            model.addAttribute("loginUser",user);
            return "show";
        }else{
            model.addAttribute("msg","登录失败,请检查账号密码信息..");
            return "login";
        }
    }
    @RequestMapping("/login")
    public String ft_login() {
        return "login";
    }
    @RequestMapping("/show")
    public String ft_show() {
        return "show";
    }
}

(5)创建前端页面

login.html的代码:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<h3 th:text="${msg}">title</h3>
<form action="/login" method="post">
    <input type="text" name="userName"><br>
    <input type="password" name="password"><br>
    <input type="submit" value="登录">
</form>
</body>
</html>

show.html的代码:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>显示页面</title>
</head>
<body>
<h3 th:text="${msg}">title</h3>
账号:<p th:text="${loginUser.userName}">账号xxx</p>
密码:<p th:text="${loginUser.password}">密码xxx</p>
</body>
</html>

(6)修改主类

在TestInterceptorApplication类中加入注解,注入控制器类和web配置类。修改后的代码如下:

package com.example.test_interceptor;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = {"controller"})
@ComponentScan(basePackages = {"config"})
public class TestInterceptorApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestInterceptorApplication.class, args);
    }

}

4.3 测试