spring boot 过滤器拦截器与aop

news2024/9/20 6:15:05

目录

一、过滤器 (Filter) 

1.1 什么是过滤器

1.2 springboot配置过滤器

方式一:使用@WebFilter

二、拦截器(Interceptor) 

2.1 什么是拦截器

2.2 使用拦截器方法

三、拦截器&过滤器与spring aop的区别

3.1 区别

3.2添加aop


适用场景:

        拦截器的应用场景:权限控制,日志打印,参数校验

        过滤器的应用场景:跨域问题解决,编码转换,shiro权限过滤

一、过滤器 (Filter

1.1 什么是过滤器

 过滤器Filter基于Servlet实现,过滤器在spring上一层,所以不能通过@Component注解交给spring 管理。但是拦截器可以通过@Component交给spring管理。

过滤器的主要应用场景是对字符编码、跨域等问题进行过滤。Servlet的工作原理是拦截配置好的客户端请求,然后对Request和Response进行处理。

Filter过滤器随着web应用的启动而启动,只初始化一次。

在开发过程中,拦截器用的很少,大部分使用场景都是过滤器。

1.2 springboot配置过滤器

方式一:使用@WebFilter

1、创建过滤器

  • 1、创建过滤器,实现接口Filter:
  • 2、使用注解@WebFilter(filterName="xxFilter",urlPatterns="/**")
  • 3、实现doFilter方法

2、将过滤器交给spring管理

  • 1、在@Configuration类手动配置过滤器,@Bean标识FilterRegistrationBean

1、创建过滤器,实现接口Filter

在Controller包中,创建MyFilter过滤器,实现Filter接口

package com.example.com_chenshuai.Controller;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

// 过滤器
@Slf4j
@WebFilter(filterName = "myFilter",urlPatterns = "/*")
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化时调用
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        log.info("filter begin ...");
        // 强转
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        // 获取请求url
        String requestURI = request.getRequestURI();
        // 获取请求 参数
        String requestParameter = request.getParameter("");

        // FilterChain类似于责任链,
        // 继续调用下一个过滤器,如果下一个没有过滤器,则继续往下走(比如调用业务代码之类的)。
        filterChain.doFilter(servletRequest,servletResponse);

        // 如果基于url进行拦截,可以使用过滤器
        // servletResponse 是返回结果,过滤器可以改写返回结果。
        // 拦截器,我们也可以获取请求的url、参数等。也可以获取返回结果。但是我们不会在拦截器里改写返回结果。
        // 在开发过程中,拦截器用的很少,大部分使用场景都是过滤器。
        // 过滤器在spring上一层,所以不能通过spring注入过滤器的实例。但是拦截器可以通过spring注入。
        // aop不能获取请求的参数等信息,和返回结果。aop能获取到调用的类,方法及方法参数。以及方法的返回值。
        // 如果想通过方法判断,需要使用aop。如果想通过请求判断,需要使用过滤器。
    }

    @Override
    public void destroy() {
        // 销毁时调用
        Filter.super.destroy();
    }
}

注解@WebFilter(filterName = "myFilter",urlPatterns = "/*")

filterName = "xxFilter",设置过滤器名称

urlPatterns = "/*",设置过滤的url,这里/*表示过滤所有的url。

方法介绍:

 init() :web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。(这个我们不需要太关注)

destroy() 当容器销毁 过滤器实例时调用该方法,一般在方法中销毁或关闭资源,在过滤器 Filter 的整个生命周期也只会被调用一次(这个我们不需要太关注)

doFilter() :该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain用户访问后续过滤器。

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) 

我们可以通过ServletRequest servletRequest 获取请求的相关信息,比如url、参数等。(这里需要先强转成HttpServletRequest)

       // 强转
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        // 获取请求url
        String requestURI = request.getRequestURI();
        // 获取请求 参数
        String requestParameter = request.getParameter("");

 我们可以通过ServletResponse servletResponse 获得请求的返回结果。我们可以通过过滤器来改写返回结果。

FilterChain filterChain 类似于责任链。

  // 继续调用下一个过滤器,如果下一个没有过滤器,则继续往下走(比如调用业务代码之类的)
        filterChain.doFilter(servletRequest,servletResponse);

责任链相关资料:

责任链设计模式_做测试的喵酱的博客-CSDN博客

2、将过滤器交给spring管理

在@Configuration类手动配置过滤器,@Bean标识FilterRegistrationBean

一、Spring管理类&注入实例_做测试的喵酱的博客-CSDN博客

package com.example.com_chenshuai.configuration;

import com.example.com_chenshuai.Controller.LoginInterceptor;
import com.example.com_chenshuai.Controller.MyFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class BaseConfiguration {


    // 将这个类交给spring管理。不使用注解的方式,因为使用注解,需要在源码上@Component
    // 使用方法,返回@Bean
    // FilterRegistrationBean 这个类,是第三方的,我们不能加@Component
    @Bean
    public FilterRegistrationBean<MyFilter> getFilter(){
        FilterRegistrationBean<MyFilter> filter = new FilterRegistrationBean<MyFilter>(new MyFilter());
        return filter;

    }
}

我们将过滤器交给spring管理,就可以了。不需要关注工程是如何调用过滤器的。(应该是通过监听方式调用的 )

 

二、拦截器(Interceptor

2.1 什么是拦截器

 拦截器(Interceptor)同 Filter 过滤器一样,它俩都是面向切面编程——AOP 的具体实现。你可以使用 Interceptor 来执行某些任务,例如在 Controller 处理请求之前编写日志,添加或更新配置……,在 Spring中,当请求发送到 Controller 时,在被Controller处理之前,它必须经过 Interceptors(0或多个)。

2.2 使用拦截器方法

1、创建拦截器,实现接口HandlerInterceptor。并通过注解@Component交给Spring管理

package com.example.com_chenshuai.Controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// 拦截器
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 拦截器,我们也可以获取请求的url、参数等。也可以获取返回结果。
        log.info("interceptor  pre begin..");
        String token = request.getHeader("token");
        if(token !=null&&token.equals("1234")){
            log.info("login success");
            // return true 继续往下走,调用下一个拦截器
            return true;

        }
        // return false 就拦截该请求
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("interceptor  post begin..");

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("interceptor  afterCompletion");
    }
}

方法解释:

preHandler(HttpServletRequest request, HttpServletResponse response, Object handler)

方法在请求处理之前被调用。该方法在 Interceptor 类中最先执行,用来进行一些前置初始化操作或是对当前请求做预处理,也可以进行一些判断来决定请求是否要继续进行下去。该方法的返回至是 Boolean 类型,当它返回 false 时,表示请求结束,后续的 Interceptor 和 Controller 都不会再执行;当它返回为 true 时会继续调用下一个 Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候就会调用当前请求的 Controller 方法。 

我们可以通过request,获取用户请求的相关信息,如url、参数、header等等。

String token = request.getHeader("token");

我们可以通过response获取,请求的返回结果。做相应的处理

postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 

方法在当前请求处理完成之后,也就是 Controller 方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对 Controller 处理之后的 ModelAndView 对象进行操作。

afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 

方法需要在当前对应的 Interceptor 类的 preHandle 方法返回值为 true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行。此方法主要用来进行资源清理。

2、在配置类@Configuration中配置

配置类需要实现接口 WebMvcConfigurer,然后重写addInterceptors

package com.example.com_chenshuai.configuration;

import com.example.com_chenshuai.Controller.LoginInterceptor;
import com.example.com_chenshuai.Controller.MyFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class BaseConfiguration implements WebMvcConfigurer {


    // 将这个类交给spring管理。不使用注解的方式,因为使用注解,需要在源码上@Component
    // 使用方法,返回@Bean
    // FilterRegistrationBean 这个类,是第三方的,我们不能加@Component
    @Bean
    public FilterRegistrationBean<MyFilter> getFilter(){
        FilterRegistrationBean<MyFilter> filter = new FilterRegistrationBean<MyFilter>(new MyFilter());
        return filter;

    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration interceptorRegistration = registry.addInterceptor(new LoginInterceptor());
        // 哪些请求被拦截
        // 注意,这里是两个*
        interceptorRegistration.addPathPatterns("/**");
        // 哪些请求不被拦截
//        interceptorRegistration.excludePathPatterns();

    }
}

在 addInterceptors方法中,addPathPatterns表示对哪些请求进行拦截。/**这里表示所有的请求。注意是2个*

        // 哪些请求被拦截
        // 注意,这里是两个*
        interceptorRegistration.addPathPatterns("/**");

excludePathPatterns表示哪些请求 ,不被拦截

        // 哪些请求不被拦截
//        interceptorRegistration.excludePathPatterns("");

三、拦截器&过滤器与spring aop的区别

过滤器是基于方法回调实现的。拦截器是基于反射实现的。

3.1 区别

作用域大小不一样。

过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后。

拦截器 Interceptor 是在请求进入servlet后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。

过滤器/拦截器与aop获取的信息不一样。过滤器/拦截器获取的是请求级别的信息,如url、传参、header、返回值等信息。

aop不能获取请求的参数等信息,和返回结果。aop能获取到调用的类,方法及方法参数。以及方法的返回值。

如果想通过方法进行拦截/过滤等处理,需要使用aop。如果想通过请求判断,需要使用过滤器。但是aop获取的是方法级别的信息,类、方法、方法的传参等等。

3.2添加aop

Spring AOP面向切面编程_做测试的喵酱的博客-CSDN博客

编写aop类

package com.example.com_chenshuai.Controller;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Slf4j
@Component
public class MyAspect {

    // 设置切点
    @Pointcut("execution(public * com.example.com_chenshuai.Controller.*.*(..) )")
    public void my(){

    }

    //
    @Before("my()")
    public void before(JoinPoint joinPoint){
        // 获得方法的参数
        Object[] args = joinPoint.getArgs();

        log.info("aspect before....");
    }

    @After("my()")
    public void after(){
        log.info("aspect after....");
    }
}

在@Configuration配置类中,添加注解@EnableAspectJAutoProxy就可以了。

package com.example.com_chenshuai.configuration;

import com.example.com_chenshuai.Controller.LoginInterceptor;
import com.example.com_chenshuai.Controller.MyFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableAspectJAutoProxy
public class BaseConfiguration implements WebMvcConfigurer {


    // 将这个类交给spring管理。不使用注解的方式,因为使用注解,需要在源码上@Component
    // 使用方法,返回@Bean
    // FilterRegistrationBean 这个类,是第三方的,我们不能加@Component
    @Bean
    public FilterRegistrationBean<MyFilter> getFilter(){
        FilterRegistrationBean<MyFilter> filter = new FilterRegistrationBean<MyFilter>(new MyFilter());
        return filter;

    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration interceptorRegistration = registry.addInterceptor(new LoginInterceptor());
        // 哪些请求被拦截
        // 注意,这里是两个*
        interceptorRegistration.addPathPatterns("/**");
        // 哪些请求不被拦截
//        interceptorRegistration.excludePathPatterns("");

    }
}

 参考:

拦截器和过滤器_学习中的小亮的博客-CSDN博客_拦截器与过滤器

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

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

相关文章

Vue3中jsx父子传值、provide和inject、v-memo指令、Teleport内置组件、KeepAlive缓存组件、transition过渡组件

文章目录1. jsx父子传值2. provide和inject3. v-memo指令4. Teleport内置组件5. KeepAlive缓存组件6. transition过渡组件1. jsx父子传值 父组件&#xff1a; <template><div><child :title"title" :setTitle"setTitle" /></div>…

GitHub下载量过百万,阿里P8秘密分享的「亿级并发系统设计」真香

随着互联网的不断发展&#xff0c;CPU硬件的核心数也在不断进步&#xff0c;并发编程越来越普及&#xff0c;但是并发编程并不像其他业务那样直接了当。在编写并发程序时&#xff0c;我们常常都会出现各种漏洞&#xff0c;这些问题往往都突然出现&#xff0c;然后又迅速消失&am…

Java编码与解码

首先区分加密与编码并不是一回事&#xff0c; 本节主要讲述常见的三种编解码方式&#xff0c;分别为&#xff1a;Unicode、URL、Base64。 常见编码算法&#xff1a; Unicode编码&#xff1a;每一字符都可变成以 \u 开头&#xff0c;长度为6的字符串。URL编码&#xff1a;以百分…

Java并发编程--多线程间的同步控制和通信

使用多线程并发处理&#xff0c;目的是为了让程序更充分地利用CPU &#xff0c;好能加快程序的处理速度和用户体验。如果每个线程各自处理的部分互不相干&#xff0c;那真是极好的&#xff0c;我们在程序主线程要做的同步控制最多也就是等待几个工作线程的执行完毕&#xff0c;…

JS表达式完全攻略

在语法概念中&#xff0c;运算符属于词&#xff0c;表达式属于短语。表达式由一个或多个运算符、操作数组成的运算式。表达式的功能是执行计算&#xff0c;并返回一个值。 表达式的形式 表达式是一个比较富有弹性的运算单元。简单的表达式就是一个直接量、常量或变量。例如&a…

【优化调度】粒子群算法求解水火电调度优化问题【含Matlab源码 1181期】

⛄一、粒子群算法简介 1 引言 自然界中的鸟群和鱼群的群体行为一直是科学家的研究兴趣所在。生物学家Craig Reynolds在1987年提出了一个非常有影响的鸟群聚集模型&#xff0c;在他的仿真中&#xff0c;每一个个体都遵循&#xff1a;避免与邻域个体相撞&#xff1a;匹配邻域个体…

Java面向对象之——封装

文章目录前言一、封装的概念二、何为封装&#xff1f;三、封装拓展——包&#x1f351;1、包的概念&#x1f351;2、导入包中的类&#x1f351;3、自定义包&#x1f351;4、常见的包四、访问限定符&#x1f351;1、public修饰符&#x1f351;2、private修饰符&#x1f351;3、默…

软件产品确认测试包括哪些方面

1.技术方面 确认测试又称有效性测试&#xff0c;是在模拟的环境下&#xff0c;运用黑盒测试的方法&#xff0c;验证被测软件是否满足需求规格说明书列出的需求。 确认测试的目的是向未来的用户表明系统能够像预定要求那样工作。经集成测试后&#xff0c;已经按照设计把所有的模…

Docker 下 jitsi-meet 视频服务器 安装部署

一、参考网站 官网文档地址&#xff1a;Self-Hosting Guide - Docker | Jitsi Meet 二、Docker 版本 三、安装部署 3.1、下载并解压缩安装包 地址&#xff1a;Release stable-8044: release jitsi/docker-jitsi-meet GitHub CSDN地址&#xff1a;docker-jitsi-meet-stab…

visdom安装及使用

目录1. 安装visdom的流程2. 使用流程1. 安装visdom的流程 重点参考链接&#xff1a;visdom安装出现Downloading scripts, this may take a little while然后就不动了 先去到github直接下载了visdom的压缩包&#xff1a;https://github.com/fossasia/visdom然后将visdom-maste…

第七章 数学 6 AcWing 1593. 整数分解

第七章 数学 6 AcWing 1593. 整数分解 原题链接 AcWing 1593. 整数分解 算法标签 数学 数论 DP 背包问题 思路 类似AcWing 12. 背包问题求具体方案 把n看成背包的容积N 因为n最多不超过400&#xff0c;然而p进制最少为2 所以物品的价值最大可以取到20(因为20^2 400) 所以…

Python读取CSV文件,数值精度丢失

Excel保存为csv以后&#xff0c;大数值的列&#xff0c;会把转换为科学计数法&#xff0c;而且后边几位都会被转为0. 搞了很多方法,最后直接安装 openpyxl 组件 和 pandas&#xff0c; 读取Excel文件就行了。 data pd.read_excel("C:/work/20221111AI/cleaned_data_noTi…

第二章 计算机算术

数据表示决定了计算机所执行操作的类型&#xff0c;数据从一个位置传到另一个位置的方法&#xff0c; 以及对存储元件的特性要求。浮点运算是非常重要的&#xff0c;因为它的实现决定了计算机执行复杂图形变换和图像处理的速度&#xff0c; 而且浮点运算对计算的准确度也有很重…

高通平台开发系列讲解(mm-camera篇)MM-CAMERA框架

文章目录 一、Camera软件位置1.1、开源代码1.2、专有源码二、摄像头前端(Camera Frontend)2.1、整体框架2.2、 Camera HAL与mm-camera交互沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要介绍高通平台mm-camera代码框架。 一、Camera软件位置 QTI 针对 An…

Flink 状态编程

状态编程有状态算子状态的管理状态的分类按键分区状态&#xff08;Keyed State&#xff09;支持的结构类型代码实现状态生存时间&#xff08;TTL&#xff09;算子状态&#xff08;Operator State&#xff09;基本概念和特点状态类型代码实现广播状态&#xff08;Broadcast Stat…

DFP 数据转发协议应用实例 .与其它厂商 LoRA 设备匹配

DFP 数据转发协议应用实例 5.与其它厂商 LoRA 设备匹配 DFP 是什么&#xff1f; 稳控科技编写的一套数据转发规则&#xff0c; 取自“自由转发协议 FFP&#xff08;Free Forward Protocol&#xff09;” &#xff0c;或者 DFP&#xff08;DoubleF Protocol&#xff09;&#xf…

【优化求解】粒子群算法求解仓库成本控制优化问题【含Matlab源码 1577期】

⛄一、粒子群算法简介 1 引言 自然界中的鸟群和鱼群的群体行为一直是科学家的研究兴趣所在。生物学家Craig Reynolds在1987年提出了一个非常有影响的鸟群聚集模型&#xff0c;在他的仿真中&#xff0c;每一个个体都遵循&#xff1a;避免与邻域个体相撞&#xff1a;匹配邻域个体…

基于JAVA的网上图书商城参考【数据库设计、源码、开题报告】

数据库脚本下载地址&#xff1a; https://download.csdn.net/download/itrjxxs_com/86427643 主要使用技术 Struts2HibernateJSPCSSJSMysql 功能介绍 系统有五类用户&#xff0c;分别是&#xff1a;会员用户&#xff0c;商品管理员&#xff0c;订单管理员&#xff0c;会员管…

【MSSQL】SQL SERVER导入中文乱码问题解决

公司最近承接了一个项目&#xff0c;甲方现使用旧版SiteServer框架&#xff08;以下简称“SiteCMS”&#xff09;作为门户网站&#xff0c;使用的数据源是SQL Server。 现在需要对SiteCMS进行升级&#xff0c;在升级时数据库和数据库结构也需要同时更新&#xff0c;其中数据库…

硬件顶配、数字先行,路特斯重塑「智能座舱」

诚然&#xff0c;在车联网的高度普及、5G技术的铺开以及汽车产业融合的大势下&#xff0c;传统单一驾驶与乘坐功能的汽车座舱正在被颠覆&#xff0c;更高级、更智能的“智能座舱”应运而生。 从行业发展态势来看&#xff0c;大屏多屏已经是智能汽车的基本操作&#xff0c;智能…