springmvc 拦截器、过滤器、AOP

简介

  1. 过滤器:filter基于回调函数,我们需要实现的filter接口中doFilter方法就是回调函数,由于filter是基于servlet的所以,filter不能使用Spring 的容器,也不支持 @Value等Spring 标签
  2. 拦截器: interceptor拦截器则基于java本身的反射机制,java.lang.reflect,使用对象的代理模式。Spring Web MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。要注意拦截器放的位置顺序拦截器的机制基于aop 面向切面编程
  3. AOP:@Aspect与Interceptor的都是基于spring aop的实现,@Aspect粒度更细

顺序

请求->>过滤器->>拦截器-->Aspect->>拦截器->>过滤器->>响应

拦截规则越来越细致,执行顺序依次是过滤器、拦截器、切面。一般情况下数据被过滤的时机越早对服务的性能影响越小,因此我们在编写相对比较公用的代码时,优先考虑过滤器,然后是拦截器,最后是aop。

比如权限校验 :应该使用过滤器在最顶层做校验

日志记录:牵扯到业务逻辑完成前后的日志记录考虑到使用AOP实现

区别

1、拦截器是基于Java的反射机制,动态代理。过滤器是基于java的函数回调

2、拦截器不依赖于servlet容器,而过滤器依赖于servlet容器

3、拦截器只能对action请求起作用(controller层),过滤器几乎对所有的请求起作用(包括静态资源,图片等)

4、拦截器可以获取IOC容器中的各个bean,包括容器上下文。过滤器不行,在拦截器中注入一个service可以调用逻辑业务

5、在action生命周期中,拦截器可以被多次调用,过滤器只能在servlet溶初始化是调用一次

6、aop 和 拦截器一样,颗粒度更细,更灵活,可以专门基于方法

过滤器

过滤器拦截的是URL

Spring中自定义过滤器(Filter)一般只有一个方法,返回值是void,当请求到达web容器时,会探测当前请求地址是否配置有过滤器,有则调用该过滤器的方法(可能会有多个过滤器),然后才调用真实的业务逻辑,至此过滤器任务完成。过滤器并没有定义业务逻辑执行前、后等,仅仅是请求到达就执行。

特别注意:过滤器方法的入参有request,response,FilterChain,其中FilterChain是过滤器链,使用比较简单,而request,response则关联到请求流程,因此可以对请求参数做过滤和修改,同时FilterChain过滤链执行完,并且完成业务流程后,会返回到过滤器,此时也可以对请求的返回数据做处理。

 

拦截器

拦截器拦截的是URL

拦截器有三个方法,相对于过滤器更加细致,有被拦截逻辑执行前、后等。Spring中拦截器有三个方法分别表示如下

  • preHandle 表示被拦截的URL对应的方法执行前的自定义处理
  • postHandle 表示此时还未将modelAndView进行渲染,被拦截的URL对应的方法执行后的自定义处理,。
  • afterCompletion:表示此时modelAndView已被渲染,执行拦截器的自定义处理。

 

AOP(面向切面)

面向切面拦截的是类的元数据(包、类、方法名、参数等)

AOP相对于拦截器更加细致,而且非常灵活,拦截器只能针对URL做拦截,而AOP针对具体的代码,能够实现更加复杂的业务逻辑。

 

1.过滤器实现

配置ip过滤器

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

@WebFilter(filterName = "SafeIpFilter", urlPatterns = {"/*"})
public class SafeIpFilter implements Filter {


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        String host = servletRequest.getServerName();
        System.out.println(host);
        System.out.println(servletRequest.getRemoteHost());
        if (1 == 1) {
            System.out.println("终止");
            return;
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

启动类中增加过滤器扫描注解

@SpringBootApplication
@EnableScheduling
@ServletComponentScan
public class ProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }

}

2、拦截器实现

添加拦截器到webMvc

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {


    @Autowired
    private SafeIpInterceptor safeIpInterceptor;

    /**
     * 添加过滤器
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(safeIpInterceptor)
                .addPathPatterns("/**");

    }
}

实现拦截器逻辑


import org.springframework.lang.Nullable;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

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

@Component
public class SafeIpInterceptor extends HandlerInterceptorAdapter {
    private static final Logger logger = LoggerFactory.getLogger(SafeIpInterceptor.class);



    /**
     * This implementation always returns {@code true}.
     * 进入 Handler方法之前执行 、用于身份认证、身份授权、比如身份认证,如果认证通过表示当前用户没有登陆,需要此方法拦截不再向下执行
     * @param request
     * @param response
     * @param handler
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return super.preHandle(request, response, handler);
    }

    /**
     * This implementation is empty.
     *   进入Handler方法之后,返回modelAndView之前执行,应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * This implementation is empty.
     * 执行Handler完成执行此方法,应用场景:统一异常处理,统一日志处理
     * @param request
     * @param response
     * @param handler
     * @param ex
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        super.afterCompletion(request, response, handler, ex);
    }

    /**
     * This implementation is empty.
     *
     * @param request
     * @param response
     * @param handler
     */
    @Override
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        super.afterConcurrentHandlingStarted(request, response, handler);
    }
}

此处可以参考:SpringBoot 通过拦截器验证Referer 防御CSRF攻击

3、AOP

此处可以参考:springboot-AOP

利用java 的动态代理模拟spring的AOP

spring aop注解失效之谜

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值