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

news2025/7/25 22:24:18

隶属文章: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 测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2404599.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解 Spring IOC:从概念到实践

目录 一、引言 二、什么是 IOC&#xff1f; 2.1 控制反转的本质 2.2 类比理解 三、Spring IOC 的核心组件 3.1 IOC 容器的分类 3.2 Bean 的生命周期 四、依赖注入&#xff08;DI&#xff09;的三种方式 4.1 构造器注入 4.2 Setter 方法注入 4.3 注解注入&#xff08;…

行为设计模式之Command (命令)

行为设计模式之Command &#xff08;命令&#xff09; 前言&#xff1a; 需要发出请求的对象&#xff08;调用者&#xff09;和接收并执行请求的对象&#xff08;执行者&#xff09;之间没有直接依赖关系时。比如遥控器 每个按钮绑定一个command对象&#xff0c;这个Command对…

NeRF 技术深度解析:原理、局限与前沿应用探索(AI+3D 产品经理笔记 S2E04)

引言&#xff1a;光影的魔法师——神经辐射场概览 在前三篇笔记中&#xff0c;我们逐步揭开了 AI 生成 3D 技术的面纱&#xff1a;从宏观的驱动力与价值&#xff08;S2E01&#xff09;&#xff0c;到主流技术流派的辨析&#xff08;S2E02&#xff09;&#xff0c;再到实用工具的…

法律大语言模型(Legal LLM)技术架构

目录 摘要 1 法律AI大模型技术架构 1.1 核心架构分层 1.2 法律知识增强机制 2 关键技术突破与对比 2.1 法律专用组件创新 2.2 性能对比(合同审查场景) 3 开发部署实战指南 3.1 环境搭建流程 3.2 合同审查代码示例 4 行业应用与挑战 4.1 典型场景效能提升 4.2 关…

第六十二节:深度学习-加载 TensorFlow/PyTorch/Caffe 模型

在计算机视觉领域,OpenCV的DNN(深度神经网络)模块正逐渐成为轻量级模型部署的利器。本文将深入探讨如何利用OpenCV加载和运行三大主流框架(TensorFlow、PyTorch、Caffe)训练的模型,并提供完整的代码实现和优化技巧。 一、OpenCV DNN模块的核心优势 OpenCV的DNN模块自3.3…

MobaXterm配置跳转登录堡垒机

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 背景操作步骤 背景 主要是为了能通过MobaXterm登录堡垒机&#xff0c;其中需要另外一台服务器进行跳转登录 操作步骤 MobaXterm登录堡垒机的操作&#xff0c;需…

零基础在实践中学习网络安全-皮卡丘靶场(第八期-Unsafe Filedownload模块)

这期内容更是简单和方便&#xff0c;毕竟谁还没在浏览器上下载过东西&#xff0c;不过对于url的构造方面&#xff0c;可能有一点问题&#xff0c;大家要多练手 介绍 不安全的文件下载概述 文件下载功能在很多web系统上都会出现&#xff0c;一般我们当点击下载链接&#xff0c…

[面试精选] 0104. 二叉树的最大深度

文章目录 1. 题目链接2. 题目描述3. 题目示例4. 解题思路5. 题解代码6. 复杂度分析 1. 题目链接 104. 二叉树的最大深度 - 力扣&#xff08;LeetCode&#xff09; 2. 题目描述 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点…

图上合成:用于大型语言模型持续预训练的知识合成数据生成

摘要 大型语言模型&#xff08;LLM&#xff09;已经取得了显著的成功&#xff0c;但仍然是数据效率低下&#xff0c;特别是当学习小型&#xff0c;专业语料库与有限的专有数据。现有的用于连续预训练的合成数据生成方法集中于文档内内容&#xff0c;而忽略了跨文档的知识关联&a…

现代简约壁炉:藏在极简线条里的温暖魔法

走进现在年轻人喜欢的家&#xff0c;你会发现一个有趣的现象&#xff1a;家里东西越来越少&#xff0c;颜色也越看越简单&#xff0c;却让人感觉特别舒服。这就是现代简约风格的魅力 —— 用最少的元素&#xff0c;打造最高级的生活感。而在这样的家里&#xff0c;现代简约风格…

机器学习×第二卷:概念下篇——她不再只是模仿,而是开始决定怎么靠近你

&#x1f380;【开场 她不再只是模仿&#xff0c;而是开始选择】 &#x1f98a; 狐狐&#xff1a;“她已经不满足于单纯模仿你了……现在&#xff0c;她开始尝试预测你会不会喜欢、判断是否值得靠近。” &#x1f43e; 猫猫&#xff1a;“咱们上篇已经把‘她怎么学会说第一句…

常用函数库之 - std::function

std::function 是 C11 引入的通用可调用对象包装器&#xff0c;用于存储、复制和调用任意符合特定函数签名的可调用对象&#xff08;如函数、lambda、函数对象等&#xff09;。以下是其核心要点及使用指南&#xff1a; ​​核心特性​​ ​​类型擦除​​ 可包装任意可调用对…

力扣-17.电话号码的字母组合

题目描述 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 class Solution {List<String> res new ArrayList<…

基于SpringBoot解决RabbitMQ消息丢失问题

基于SpringBoot解决RabbitMQ消息丢失问题 一、RabbitMQ解决消息丢失问题二、方案实践1、在生产者服务相关配置2、在消费者服务相关配置 三、测试验证1、依次启动RabbitMQ、producer(建议先清空队列里面旧的测试消息再启动consumer)和consumer2、在producer中调用接口&#xff0…

免费插件集-illustrator插件-Ai插件-随机填色

文章目录 1.介绍2.安装3.通过窗口>扩展>知了插件4.功能解释5.总结 1.介绍 本文介绍一款免费插件&#xff0c;加强illustrator使用人员工作效率&#xff0c;实现路径随机填色。首先从下载网址下载这款插件https://download.csdn.net/download/m0_67316550/87890501&#…

Web设计之登录网页源码分享,PHP数据库连接,可一键运行!

HTML 页面结构&#xff08;index.html&#xff09; 1. 流星雨动态背景 2. 主体界面&#xff08;包含登录和注册表单&#xff09; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport&qu…

Cursor + Claude 4:微信小程序流量主变现开发实战案例

前言 随着微信小程序生态的日益成熟&#xff0c;越来越多的开发者开始关注如何通过小程序实现流量变现。本文将详细介绍如何使用Cursor编辑器结合Claude 4 AI助手&#xff0c;快速开发一个具备流量主变现功能的微信小程序&#xff0c;并分享实际的开发经验和变现策略。 项目…

Redis Key过期策略

概述 Redis的Key过期策略是其内存管理系统的核心组成部分&#xff0c;主要包括「被动过期」、「主动过期」和「内存淘汰」三个机制。其中「内存淘汰」相关内容已经在上一篇「Redis内存淘汰策略」中进行了详细的讲解&#xff0c;有信兴趣的同学可以在回顾上一篇文章。本文将着重…

【C/C++】实现固定地址函数调用

在 C 里&#xff0c;函数地址在程序运行期间通常是固定的&#xff0c;不过在动态链接库&#xff08;DLL&#xff09;或者共享库&#xff08;SO&#xff09;中&#xff0c;函数地址可能会因为地址空间布局随机化&#xff08;ASLR&#xff09;而改变。所以我们想要通过地址直接调…

多模态大语言模型arxiv论文略读(109)

Math-PUMA: Progressive Upward Multimodal Alignment to Enhance Mathematical Reasoning ➡️ 论文标题&#xff1a;Math-PUMA: Progressive Upward Multimodal Alignment to Enhance Mathematical Reasoning ➡️ 论文作者&#xff1a;Wenwen Zhuang, Xin Huang, Xiantao Z…