zoukankan      html  css  js  c++  java
  • Spring Security构建Rest服务-0400-使用切片拦截rest服务

    Restful API的拦截:

      1,过滤器(Filter)

      2,拦截器(Interceptor)

      3,切片(Aspect)

    1,过滤器

    和传统javaweb一鸟样,例,记录controller执行时间过滤器,会过滤所有url:

    /**
     * 记录执行时间过滤器
     * ClassName: TimeFilter 
     * @Description: TODO
     * @author lihaoyang
     * @date 2018年2月26日
     */
    @Component //声明为spring组件,springboot项目没有web.xml直接声明为组件
    public class TimeFilter implements Filter {
    
        @Override
        public void destroy() {
            System.err.println("time filter destory...");
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            System.err.println("time filter start");
            long startTime = new Date().getTime();
            chain.doFilter(request, response); //执行其他过滤器链
            System.err.println("time filter 耗时:"+(new Date().getTime()-startTime));
            System.err.println("time filter end");
        }
    
        @Override
        public void init(FilterConfig arg0) throws ServletException {
            System.err.println("time filter init...");
        }
    
    }

    在传统javaweb我们需要在web.xml配置过滤器,springboot没有web.xml,只需要在类上加上@Component注解告诉spring这是一个组件即可。如果我们需要引入第三方的一些过滤器,是没办法加注解的,此时就需要使用java来代替配置文件了:

    假设自定义的TimeFilter即为第三方Filter,注释掉@Component注解

    只需加上一个配置类,相当于xml配置即可:

    package com.imooc.web.config;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import com.imooc.web.filter.TimeFilter;
    
    
    @Configuration
    public class WebConfig {
    
        @Bean
        public FilterRegistrationBean timeFilter(){
            FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
            
            TimeFilter timeFilter = new TimeFilter();
            filterRegistrationBean.setFilter(timeFilter);
            //指定要过滤的url
            List<String> urls = new ArrayList<>();
            urls.add("/*");
            filterRegistrationBean.setUrlPatterns(urls);
            return filterRegistrationBean;
        }
    }

    filter只能对request和response进行操作,因为他是J2EE的规范,所以这个请求最终是哪一个controller的哪个方法来处理的是不知道的。因为controller是spring的概念。如果需要知道这些信息,就需要用拦截器。

    2,拦截器

    自定义拦截器,加上@Component 声明为spring组件,记录调用耗时:

    package com.imooc.web.interceptor;
    
    import java.util.Date;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.stereotype.Component;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    /**
     * 记录调用耗时的拦截器
     * ClassName: TimeInterceptor 
     * @Description: TODO
     * @author lihaoyang
     * @date 2018年2月26日
     */
    @Component //声明为spring组件
    public class TimeInterceptor implements HandlerInterceptor{
    
        //进入controller之前执行
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.err.println("preHandle...");
            
            System.err.println(((HandlerMethod)handler).getBean().getClass().getName());//哪个类
            System.err.println(((HandlerMethod)handler).getMethod()); //哪个方法
            request.setAttribute("startTime", new Date().getTime());//调用开始计时
            return true;
        }
    
        //进入controller之中执行
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
                throws Exception {
            System.err.println("postHandle...");
            Long start = (Long) request.getAttribute("startTime");
            System.err.println("time interceptor 耗时:"+(new Date().getTime()-start));
        }
    
        //controller执行完之后执行
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
                throws Exception {
            
            System.err.println("afterCompletion...");
            Long start = (Long) request.getAttribute("startTime");
            System.err.println("time interceptor 耗时:"+(new Date().getTime()-start));
            //如果调用有异常,这个Exception会有信息
            System.err.println("exception:"+ex);
        }
    
    }

    java配置,继承WebMvcConfigurerAdapter类重写addInterceptors方法,定义自己的拦截器

    package com.imooc.web.config;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    import com.imooc.web.filter.TimeFilter;
    import com.imooc.web.interceptor.TimeInterceptor;
    
    
    @Configuration
    public class WebConfig extends WebMvcConfigurerAdapter{
    
        //由于TimeInterceptor声明为了spring组件,直接注入进来
        @Autowired
        private TimeInterceptor timeInterceptor;
        /**
         * 实现WebMvcConfigurerAdapter,重写addInterceptors方法添加拦截器
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(timeInterceptor);
        }
    
        @Bean
        public FilterRegistrationBean timeFilter(){
            FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
            
            TimeFilter timeFilter = new TimeFilter();
            filterRegistrationBean.setFilter(timeFilter);
            //指定要过滤的url
            List<String> urls = new ArrayList<>();
            urls.add("/*");
            filterRegistrationBean.setUrlPatterns(urls);
            return filterRegistrationBean;
        }
    }

    调用http://localhost:8080/user/1

    可以看到能获取到所调用的Controller以及哪个方法:

    time filter start
    preHandle...
    com.imooc.web.controller.UserController
    public com.imooc.dto.User com.imooc.web.controller.UserController.getInfo(java.lang.String)
    afterCompletion...
    time interceptor 耗时:34
    exception:null
    time filter 耗时:50
    time filter end
    time filter start
    time filter 耗时:15
    time filter end

     注意,如果是抛出了自定义异常,做过了处理,afterCompletion里就不会打印异常信息了。

    拦截器能获取到所要处理的控制器类和方法,但是没办法获取到具体要处理的参数,查看DispatcherServlet源码的doDispatch方法就可以看到,执行拦截器的时候,还没有组装参数,把请求的参数映射成为contrller里的参数,所以取不到具体的参数值,如果想获取参数值,就需要用到第三个拦截机制spring的AOP,自定义切面

    3,切片

    TimeAspect切面类:

    package com.imooc.web.aspect;
    
    import java.util.Date;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.stereotype.Component;
    
    /**
     * 调用耗时切片
     * ClassName: TimeAspect 
     * @Description: TODO
     * @author lihaoyang
     * @date 2018年2月26日
     */
    @Aspect
    @Component
    public class TimeAspect {
    
        /**
         * 
         */
        @Around("execution(* com.imooc.web.controller.UserController.*(..))")
        public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable{
            System.err.println(">>>> 进入  TimeAspect start  >>>>>");
            
            Object[] args = pjp.getArgs();
            if(args.length > 0){
                for (Object arg : args) {
                    System.err.println("arg is "+arg);
                }
            }
            long start = new Date().getTime();
            
            Object object = pjp.proceed();
            System.err.println("TimeAspect 调用耗时:"+(new Date().getTime()-start));
            System.err.println(">>>>   TimeAspect 结束  >>>>>");
            
            return object;
        }
    }

    访问:http://localhost:8080/user/1可以看到能够取到参数1

    =======time filter start======
    ++++++ 进入 preHandle...+++++++
    com.imooc.web.controller.UserController$$EnhancerBySpringCGLIB$$533f819c
    public com.imooc.dto.User com.imooc.web.controller.UserController.getInfo(java.lang.String)
    >>>> 进入 TimeAspect start >>>>>
    arg is 1
    >>>>>>进入User Controller --> getInfo 方法
    1
    TimeAspect 调用耗时:0
    >>>> TimeAspect 结束 >>>>>
    postHandle...
    time interceptor 耗时:1
    time interceptor 耗时:1
    exception:null
    +++++ afterCompletion +++++++
    time filter 耗时:5
    =======time filter end=======
    =======time filter start======
    time filter 耗时:2
    =======time filter end=======

    三者调用顺序:

     代码github:https://github.com/lhy1234/spring-security

  • 相关阅读:
    JavaScript高级程序设计
    昨天听了林某的建议,开了自己的博客
    Unity是什么?
    依赖注入
    NHibernate 01 [简述]
    C#Delegate.Invoke、Delegate.BeginInvoke And Control.Invoke、Control.BeginInvoke
    C#调用http请求,HttpWebRequest添加http请求头信息
    JUnit入门笔记
    Spring:利用ApplicationContextAware装配Bean
    Java线程安全synchronize学习
  • 原文地址:https://www.cnblogs.com/lihaoyang/p/8472374.html
Copyright © 2011-2022 走看看