拦截器与过滤器

  1. 拦截器

   介绍:主要用于拦截用户请求并作出相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、登录验证等。

   原理:所有的拦截器 (Interceptor) 和处理器 (Handler) 都注册在 HandlerMapping 中,Spring MVC 中所有的请求都是由 DispatcherServlet 分发的。当请求进入时,首先会得到处理该请求的 Handler (即 Controller 中对应的方法)以及所有拦截该请求的拦截器

   实现:这里先定义一个拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.elite.groovy.interceptor;
 
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
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;
 
/**
 * @author Smith
 * @date 2023/8/23  17:08
 * @description 接口访问拦截器
 */
@Slf4j
@Component
public class ProxyInterceptor implements HandlerInterceptor {
 
    /**
     * 预处理回调方法,实现处理器的预处理(如登录检查)
     * 第三个参数为响应的处理器,即controller
     * 返回true,表示继续流程,调用下一个拦截器或者处理器
     * 返回false,表示流程中断,通过response产生响应
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("收到前端的请求,url:" + request.getRequestURL());
        log.info("请求参数 :" + IOUtils.toString(request.getInputStream(), "utf-8"));
        return true;
    }
 
    /**
     * 当前请求进行处理之后,也就是Controller方法调用之后执行,
     * 但是它会在DispatcherServlet 进行视图返回渲染之前被调用。
     * 此时我们可以通过modelAndView对模型数据进行处理或对视图进行处理。
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
 
    }
 
    /**
     * 方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。
     * 这个方法的主要作用是用于进行资源清理工作的。
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    }
} 

  其次配置拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.elite.groovy.config;
 
import com.elite.groovy.interceptor.ProxyInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
import java.util.ArrayList;
import java.util.List;
 
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Autowired
    private ProxyInterceptor ipInterceptor;
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(ipInterceptor)
                .addPathPatterns("/**");
    }
}
  1. 过滤器

   介绍:过滤器是Servlet的高级特性之一,是实现Filter接口的Java类。其基本功能就是对servlet的调用进行干预,在servl请求和响应的过程中增加一些特定的功能。可以使用过滤器实现的功能有:统一编码,URL级别的权限访问控制,过滤敏感词汇,压缩请求信息

   实现:

复制代码
package com.elite.ngs.filter;

import com.wisdge.web.IPUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

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

/**
 * @author smith
 * @date 2023/1/11  13:44
 */
@WebFilter(urlPatterns = {"/smsCodeSend_"}, filterName = "smsFilter")
public class SmsFilter implements Filter {
    private static final Log log = LogFactory.getLog(SmsFilter.class);
    protected RedisTemplate redisTemplate;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        ServletContext servletContext = filterConfig.getServletContext();
        WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        redisTemplate = (RedisTemplate) webApplicationContext.getBean("redisTemplate");
        log.debug("------smsFilter init!-------");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.debug("--------start smsFilter-------------");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String ip = IPUtils.getRemoteIP(request);
        log.debug("smsSend ip :" + ip);
        String smsKey = "SMS:" + ip;
        //先看Key是否存在
        boolean flag = redisTemplate.hasKey(smsKey);
        if (flag) {
            //说明上次发送验证码的时间不超过一分钟
            log.debug("smsKey exist");
        } else {
            // 第一次调用,所以value(调用次数)设置为1
            redisTemplate.opsForValue().set(smsKey, "1", 1, TimeUnit.MINUTES);
            filterChain.doFilter(request, servletResponse);
        }
    }

    @Override
    public void destroy() {
        log.debug("------smsFilter destroy----");
    }
}
复制代码

  配置filter

  第一个是上面的例子,使用WebFilter注解,但是多个filter时无法控制先后顺序,只会根据filter的首字母顺序来确定先后顺序。

  第二个是在web.xml中配置,执行顺序按配置的上下先后顺序执行

  filter标签:fliter-name:指为过滤器的名字;filter-class:过滤器的完整类名

  filter-mapping标签:fliter-name是filter标签中声明的名字;url-pattern用来设置filter所拦截的请求路径。

<filter>
    <filter-name>myFilter</filter-name>
    <filter-class>com.lsl.mylsl.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>myFilter</filter-name>
    <url-pattern>/test</url-pattern>
</filter-mapping>
<filter>
    <filter-name>myFilter</filter-name>
    <filter-class>com.lsl.mylsl.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>myFilter</filter-name>
    <url-pattern>/test</url-pattern>
</filter-mapping>
  1. 区别

  a.过滤器依赖servlet容器(tomcat等,只能在web程序中使用);而拦截器不依赖servlet容器。它是个spring组件,由spring容器管理,可以单独使用。

  b.过滤器可以拦截所有请求,包括访问静态资源的请求,拦截器只能拦截action请求,即访问controller的请求

  c.拦截器可以获取IOC容器中的各个bean,而过滤器不行。可以在拦截器里注入一个service,可以调用业务逻辑

  d.触发时机不同。过滤器是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后;拦截器是在请求进入servlet后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。

posted @   写字楼间写字员  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示