<返回更多

springboot三种拦截器

2021-05-10  今日头条  风骚的程序员
加入收藏

SpringBoot 共有三种拦截http请求方式Filter,interceptor和aop。

1、FIlter

使用Filter的时候需要在Application启动类上加入@ServletComponentScan注解

import JAVAx.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
 * 在SpringBoot中通过注解注册的方式简单的使用Filter
 * @author rayfoo
 */
@WebFilter(urlPatterns = "/*", filterName = "MyFilter")
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyFilter  Filter初始化中");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("MyFilter  开始进行过滤处理");
        //调用该方法后,表示过滤器经过原来的url请求处理方法
        chain.doFilter(request, response);
        System.out.println("MyFilter  处理后的操作");
    }

    @Override
    public void destroy() {
        System.out.println("MyFilter  Filter销毁中");
    }
}

上述代码中,重写了Filter的三个方法,分别是:

init:在此Filter被创建时执行

doFilter:处理Filter的真正业务逻辑,可以在这个方法中对请求进行放行,在放行前后都可以执行代码,也可以在此方法中进行重定向和请求转发,但是一旦使用了请求转发、重定向,抛出异常,出现异常,被拦截的路径对应的业务方法就不会被执行。

destory:在此FIlter被销毁时执行

2、Interceptor

Interceptor依赖于web框架,我们经常在Spring MVC中用到该配置,在这个场景下Interceptor 就依赖于SpringMVC框架。

使用Interceptor之前要先创建类并实现HandlerInterceptor接口

import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class MyInterceptor implements HandlerInterceptor {
    /**
     * 在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor  方法执行之前...");
        return true;
    }

    /**
     * 在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回ModelAndView,但未进行页面渲染),有机会修改ModelAndView
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor  回调操作...");
    }

    /**
     * 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面)
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        System.out.println("MyInterceptor  方法执行之后...");
    }
}

创建完实现类还需要注册Interceptor

在SpringBoot2中,建议使用的注册拦截器的方法有如下两种:

1)实现WebMvcConfigurer接口

2)继承WebMvcConfigurerAdapter类(此类也是实现了WebMvcConfigurer)

下面介绍一下实现WebMvcConfigurer方法注册拦截器

import com.xa.filter.MyInterceptor;
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;

@Configuration
public class MyConfigurer implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //1.得到自定义的拦截器
        InterceptorRegistration interceptor = registry.addInterceptor(new MyInterceptor());
        //2.需要拦截的路径 /**所有资源都拦截
        interceptor.addPathPatterns("/**");
        //3.设置不拦截的路径 (登录页需要的和静态资源)
        interceptor.excludePathPatterns("/","/index.html","/login","/css/**","/img/**","/js/**");
    }
}

3、AOP

使用AOP首先要引入jar包

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-aop</artifactId>
     <version>2.1.1.RELEASE</version>
 </dependency>

定义切面


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

@Aspect
@Component
@Order(1) //指定切面类执行顺序,数字越小越先执行
public class MyAspect {
    /**
     * 定义那个包下的执行 面向切换
     * 该示例 实现 所有controller 包下的方法执行的切面
  	 * 第一个*含义是:代表所有类型的返回值
		 * 第二个*是代表com.mall.web.controller包下的所有类
		 * 第三个是类下的所有方法,括号中两个点表示任意个形参
	*/
    @Pointcut("execution(public * com.*.controller.*.*(..))")
    public void webLog(){}

    /**
     * 请求之前 进入控制之前 执行,但是在拦截器之后执行
     * @param joinPoint
     * @throws Throwable
     */
    @Before("webLog()")
    public void deBefore(JoinPoint joinPoint) throws Throwable {
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        System.out.println("MyAspect  URL : " + request.getRequestURL().toString());
        System.out.println("MyAspect  HTTP_METHOD : " + request.getMethod());
        System.out.println("MyAspect  IP : " + request.getRemoteAddr());
        System.out.println("MyAspect  CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        System.out.println("MyAspect  ARGS : " + Arrays.toString(joinPoint.getArgs()));


    }

    /**
     * 控制器执行之后执行,得到控制器方法的返回值
     * @param ret
     * @throws Throwable
     */
    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求,返回内容
        System.out.println("MyAspect  方法的返回值 : " + ret);
    }

    //后置异常通知
    @AfterThrowing("webLog()")
    public void throwss(JoinPoint jp){
        System.out.println("MyAspect  方法异常时执行.....");
    }

    //后置最终通知,final增强,不管是抛出异常或者正常退出都会执行
    @After("webLog()")
    public void after(JoinPoint jp){
        System.out.println("MyAspect  方法最后执行.....");
    }

    //环绕通知,环绕增强,相当于 请求方法的拦截器
    @Around("webLog()")
    public Object arround(ProceedingJoinPoint pjp) {
        System.out.println("MyAspect  方法环绕start....."); // 最先执行
        try {
            Object o =  pjp.proceed();
            System.out.println("MyAspect  方法环绕proceed,结果是 :" + o); // 最后执行
            return o;
        } catch (Throwable e) {
            e.printStackTrace();
            return null;
        }
    }
}

我们新增个Controller来测试下他们的运行顺序

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class DemoController {

    @GetMapping("/demo")
    public Map test() {
        Map map = new HashMap() ;
        map.put("a","123") ;
        return map ;
    }
}

我们访问http://localhost:{port}/demo可以看到后台打印如下日志

 

springboot三种拦截器

 

可以看出他们的拦截顺序:filter—>Interceptor—->@Aspect 。以下这个图可以比较直观看出他们之间的拦截顺序

springboot三种拦截器

 

总结: 过滤器和拦截器的区别,过滤器是依赖于servlet容器(struts),在实现上基于函数回调,可以对几乎所有的请求进行过滤。但缺点是一个过滤器实例只能在容器初始化时调用一次,来进行过滤操作,获得我们想要的数据。

三者之间主要还是粒度的差异,应用场景的不同。

过滤器(Filter) :采用filter过滤器,可以获取http、http请求和响应,但无法获取与spring框架相关的信息,如哪个control处理,哪个方法处理,有哪些参数,这些都是无法获取的。

拦截器(Interceptor):采用interceptor拦截器,除了获取http、http请求和响应对象,还可以获取请求的类名、方法名,但拦截器无法获取请求参数的值。

切片 (Aspect) : 切片 aspect 可以获取传入的参数值,但无法获取原始的http,http请求和响应对象。

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>