1、认识过滤器(Filter)

1.1、过滤器的定义

过滤器是JavaWeb的三大组件之一,是实现Filter接口的Java类。

过滤器是实现对请求资源(jsp、servlet、html)的过滤功能,是一个运行在服务器的程序,优先于请求资源(jsp、servlet、html)之前执行。

当浏览器发送请求给服务器的时候,先执⾏过滤器,然后才访问Web的资源。服务器响应Response,从Web资源抵达浏览器之前,也会途径过滤器。

在很多Web开发中,都会用到过滤器(Filter),如参数过滤、防止SQL注入、防止页面攻击、过滤敏感字符、解决网站乱码、空参数矫正、Token验证、Session验证、点击率统计等。

1.2、为什么要使用过滤器

在Web开发中,经常会有这样的需求:在所有接口中去除用户输入的非法字符,以防止引起业务异常。要实现这个功能,可以有很多方法,如:

  • 在前端参数传入时进行校验,先过滤非法字符,然后返回用户界面提示用户重新输入。
  • 后端接收前端没有过滤的数据,然后过滤非法字符。
  • 利用filter处理项目中所有非法字符。

很明显,前两种实现方法会存在重复代码,因为每个前端页面或后端都需要处理,这样会导致代码很难维护。如果用过滤器来实现,则只需要用过滤器对所有接口进行过滤处理。这样非常方便,同时不会出现冗余代码。

1.3、使用Filter的步骤(以SpringBoot项目为例)

(1)新建类,实现Filter抽类类。

(2)重写init、doFilter、destroy方法。

(3)在Spring Boot入口类中添加注解@ServletComponentScan,以注册Filter。

init():该方法在容器启动初始化过滤器时被调用,它在Filter的整个生命周期只会被调用一次,这个方法必须执行成功,否则过滤器会不起作用。

doFilter():容器中的每一次请求都会调用该方法,FilterChain用来调用下一个过滤器Filter。

destroy():容器销毁时被调用。一般在方法中销毁或关闭资源,也只会被调用一次。

注意的是doFilter()方法:

@Override
public void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException{//请求(request)处理逻辑//请求(request)封装逻辑//chain重新写回request和response
}

上面的FilterChain是一个接口,里面又定义了doFilter()方法,这是因为在Java中使⽤了链式结构。把所有的过滤器都放在FilterChain⾥边,如果符合条件,就执⾏下⼀个过滤器(如果没有过滤器了,就执⾏⽬标资源)。

1.4、SpringBoot实现一个简单的过滤器

(1)首先随便写一个控制器Controller

@RestController
@Slf4j
@RequestMapping("/api/filter")
public class FilterUserController {@GetMapping("/getUserList")public List<String> getUser() {log.info("开始业务逻辑处理。");List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");log.info("业务逻辑处理结束。");return list;}
}

(2)在启动类添加一个注解,找到定义的拦截器。

@ServletComponentScan(basePackages = "com.binlog.study.filter")

(3)写一个过滤器,实现Filter

@Slf4j
@Order(1)  //如果有多个Filter,则序号越小,越早被执行
//@Component//无需添加此注解,在启动类添加@ServletComponentScan注解后,会自动将带有@WebFilter的注解进行注入!
//这里的urlPatterns为接口里的路径过滤条件
@WebFilter(filterName = "timeFilter", urlPatterns = "/api/filter/*")
public class TimeFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {log.info("初始化过滤器:{}", filterConfig.getFilterName());}@Overridepublic void destroy() {log.info("销毁过滤器");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {log.info("开始执行");long startTime = System.currentTimeMillis();filterChain.doFilter(servletRequest, servletResponse);long endTime = System.currentTimeMillis();log.info("请求:{},耗时:{}ms", getUrlFrom(servletRequest), (endTime - startTime));log.info("结束执行");}private String getUrlFrom(ServletRequest servletRequest) {if (servletRequest instanceof HttpServletRequest) {return ((HttpServletRequest) servletRequest).getRequestURL().toString();}return "";}
}

(4)项目启动后,控制台输出结果为:

项目启动后,就已经初始化过滤器了。

浏览器页面调用一下接口:http://localhost:8060/api/filter/getUserList

关闭项目后,过滤器也销毁了。

2、认识拦截器(Interceptor)

2.1、拦截器的定义

SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。

拦截器它是链式调用,一个应用中可以同时存在多个拦截器Interceptor,一个请求也可以触发多个拦截器,而每个拦截器的调用会依据它的声明顺序依次执行。

2.2、拦截器的核心API

SpringMVC拦截器提供三个方法分别是preHandle、postHandle、afterCompletion,我们就是通过重写这几个方法来对用户的请求进行拦截处理的。

  • preHandle() :这个方法将在请求处理之前进行调用。「注意」:如果该方法的返回值为false ,将视为当前请求结束,不仅自身的拦截器会失效,还会导致其他的拦截器也不再执行。
  • postHandle():只有在 preHandle() 方法返回值为true 时才会执行。会在Controller 中的方法调用之后,DispatcherServlet 返回渲染视图之前被调用。「有意思的是」:postHandle() 方法被调用的顺序跟 preHandle() 是相反的,先声明的拦截器 preHandle() 方法先执行,而postHandle()方法反而会后执行。
  • afterCompletion():只有在 preHandle() 方法返回值为true 时才会执行,在整个请求结束之后, DispatcherServlet 渲染了对应的视图之后执行。

2.3、SpringBoot实现一个登录拦截器

预想:用户在访问首页接口,先判断一下session,如果session中有user的信息,说明用户已经登录过了,能正常访问首页接口,否则跳转到登录页面,让用户进行登录。

(1)首先随便定义一个实体类

@Data
public class InterceptorUserEntity {private Integer id;private String name;
}

(2)在controller里写3个接口

@RestController
@Slf4j
@RequestMapping("/api/interceptor")
public class InterceptorUserController {@GetMapping("/setSession")@ResponseBodypublic Object setSession(HttpServletRequest request) {//将用户信息存放到session中InterceptorUserEntity user = new InterceptorUserEntity();user.setId(001);user.setName("张三");request.getSession().setAttribute("user", user);return "已进行登录!";}/*** 用户登录后跳转到首页** @return*/@GetMapping("/index")public Object index() {return "这里是首页!";}/*** 登录页面** @return*/@GetMapping("/login")public Object login() {return "请进行登录!";}
}

(3)编写拦截器,可以通过要定义的Interceptor类实现handlerInterceptor接口。

@Component
@Slf4j
public class UserInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//业务拦截相关规则//从session中获取用户的信息InterceptorUserEntity user = (InterceptorUserEntity) request.getSession().getAttribute("user");//判断用户是否登录if (null == user) {response.sendRedirect(request.getContextPath() + "/api/interceptor/login");return false;}//需要返回true,否则请求不会被控制器处理return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后),如果异常发生,则该方法不会被调用");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info("在整个请求结束之后被调用,也就是在DispatcherServlet渲染了对应的视图之后执行(主要是用于进行资源清理工作)");}
}

(4)使用@Configuration注解写一个拦截器的配置文件。

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {@Autowiredprivate UserInterceptor userInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(userInterceptor).addPathPatterns("/api/interceptor/**").excludePathPatterns("/**/login", "/**/setSession");}
}

.addPathPatterns表示作用范围。(只在这个interceptor下的所有接口进行拦截)

.excludePathPatterns表示放行。这里把登录页面和已登录完成(setSession)放行。

(其它接口都会被拦截,然后跳转到login页面)

在用户没有请求过 /interceptor/setsession的时候,如果用户请求了 /interceptor/拦截器就会发挥作用, 把它跳转到/user/login的接口上去,如果用户请求过/interceptor/setsession的话, 再去请求/user/index拦截器就会放行,请求到相应的结果。

3、过滤器与拦截器的区别

相同点:

过滤器与拦截器都体现了AOP的编程思想,都可以实现例如日志、登录鉴权等功能。

不同点:

①:拦截器是基于java的反射机制(动态代理)的实现,而过滤器是基于函数的回调。

②:拦截器不依赖于servlet容器,而过滤器依赖于servlet容器。

③:拦截器只对Controller请求起作用,而过滤器则可以对几乎所有的请求起作用。

④:拦截器可以访问Controller上下文、值、栈里面的对象,而过滤器不可以。

⑤:在spring容器的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

⑥:拦截器可以获取IOC容器中的各个bean,而过滤器不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

触发机制不同

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

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

过滤器几乎可以对所有进入容器的请求起作用,而拦截器只会对Controller中请求或访问static目录下的资源请求起作用。

【Spring学习】过滤器和拦截器相关推荐

  1. Spring Boot 过滤器与拦截器的使用及其区别 和过滤器怎么设置运行顺序

    过滤器 过滤器的定义 在客户端将请求发送到服务器端之前,拦截这些请求:在服务器端的响应返回给客户端之前,处理这些响应. 比如字符编码过滤器CharacterEncodingFilter,就是设置req ...

  2. spring boot 拦截器获取controller返回的数据_高级码农Spring Boot实战与进阶之过滤器和拦截器的使用及其区别...

    众所周知的Spring Boot是很优秀的框架,它的出现简化了新Spring应用的初始搭建以及开发过程,大大减少了代码量,目前已被大多数企业认可和使用.这个专栏将对Spring Boot框架从浅入深, ...

  3. springboot 控制台输出错误信息_高级码农Spring Boot实战进阶之过滤器、拦截器的使用...

    众所周知的Spring Boot是很优秀的框架,它的出现简化了新Spring应用的初始搭建以及开发过程,大大减少了代码量,目前已被大多数企业认可和使用.这个专栏将对Spring Boot框架从浅入深, ...

  4. 云笔记项目-过滤器与拦截器学习

    在做云笔记项目的过程中,没有登录的情况下,也可以直接访问edit.html页面.这个跟以前自己用Servlet做过的PadAndFilterManagement情况类似,当时在没有登录的情况下可以访问 ...

  5. 【学习日记2023.5.8】之 springboot案例之登录功能(会话技术_JWT令牌_过滤器_拦截器)

    文章目录 1. 案例-登录认证 1. 1登录功能 1.1.1 需求 1.1.2 接口文档 1.1.3 思路分析 1.1.4 功能开发 1.1.5 测试 1.1.6 全后端联调 1.2 登录校验 1.2 ...

  6. Spring Boot实战:过滤器、拦截器与切片

    Spring Boot实战:过滤器.拦截器与切片 Q:使用过滤器.拦截器与切片实现每个请求耗时的统计,并比较三者的区别与联系 过滤器Filter 过滤器概念 Filter是J2E中来的,可以看做是Se ...

  7. Spring Boot实战:拦截器与过滤器

    一.拦截器与过滤器 在讲Spring boot之前,我们先了解一下过滤器和拦截器.这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的.在分析两者的区别之前,我们先理解一下AOP的概念,A ...

  8. spring中的监视器,过滤器,拦截器

    1.监视器 (1)首先监视器是观察者模式的实现,在我之前的博客中有关于监视器模式的解释.监视器相当于观察者 (2)我们在springMvc中最常见的监视器 ContextLoaderlistener ...

  9. spring 两次进入拦截器_过滤器和拦截器的 6 个区别,别再傻傻分不清了

    点击上方 肉眼品世界,选择 设为星标 深度价值体系传递 作者 :程序员内点事 来源 :toutiao.com/i6834310440495874563 毕竟这两种工具开发中用到的频率都相当高,应用起来 ...

最新文章

  1. BZOJ 1061费用流
  2. 文巾解题 264. 丑数 II (剑指 Offer 49. 丑数)
  3. C. Woodcutters【贪心】
  4. liunx 下 sendmail 反病毒和防垃圾邮件
  5. Python监听剪切板的两种方法
  6. 【DP】和谐的奶牛(jzoj 1750)
  7. 44 CO配置-控制-产品成本控制-成本对象控制-实际成本核算/物料分类帐-激活实际成本的在产品
  8. 本周任务asp.net 1.1老系统移植升级到asp.net 2.0,又是一个浩大的工程啊?
  9. 怎样将树的中序遍历的数输入到一个数组中_LeetCode 530.二叉搜索树的最小绝对差
  10. python提取excel数据视频_Python-爬取b站的热门视频并导入Excel中
  11. 国产441b电子计算机,国产441B晶体管计算机文档(讲义)
  12. linux 内核网络,数据接收流程图
  13. kotlin数据类_Kotlin数据类
  14. Spring框架入门(一)
  15. java ctrl d不能用_Intellij Idea中Backspace无法使用,Ctrl+c/Ctrl+d等等快捷键无法使用的问题的解决...
  16. matlab中求最大似然估计,matlab求最大似然估计
  17. 《程序员练习生》第5期 学习编程的乐趣
  18. 通过python各种开源库,开发一个适合大部分公司测试项目框架,确定名字AutoTestProjects
  19. 【爬虫】爬取个人随手记账户
  20. 用python画圆锥_echarts 怎么画椭圆或者画圆锥

热门文章

  1. 交换机-链路冗余、链路聚合、堆叠、热备、虚拟化
  2. 被骗到香港做传销!(当事人详细回忆)
  3. HBase Windows 安装
  4. 根据流量 (Traffic) 来进行负载平衡器 (Auto Scaling Group) 的运作
  5. 基于C语言的贪吃蛇游戏开发与设计
  6. angular 系列八 ui-router详细介绍及ngRoute工具区别
  7. Java基础 — JDK和JRE的区别和环境变量配置
  8. Windows7 IP地址切换器
  9. javascript之模拟滚动条
  10. 求从1 开始第35个能被7和3整除的整数