Spring Security入门(九) 使用Spring MVC开发RESTful API-使用Filter和Interceptor拦截REST服务

一.导学
  • 如果想用RESTful API记录处理时间,就需要用下面三种拦截方式了

  • RESTful API的拦截

    • 过滤器(Filter)
    • 拦截器(interceptor)
    • 切片(Aspect)
二.过滤器(Filter)
  • 编写过滤器
@Component
public class TimeFilter implements Filter {
    @Override//初始化
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("time filter init");
    }

    @Override//过滤器逻辑
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("time filter start");
         long start = new Date().getTime();
         chain.doFilter(request,response);
        System.out.println("time filter"+(new Date().getTime()-start));
        System.out.println("time filter finish");
    }

    @Override//销毁
    public void destroy() {
        System.out.println("time filter destroy");
    }
}
    @GetMapping(value = "/{id:\\d+}")
    @JsonView(User.UserDetailView.class)
    public User getInfo(@PathVariable(name = "id") String idxxx){
//        throw new UserNotExistException(idxxx);
        System.out.println("进入getInfo服务");
        User user = new User();
        user.setUsername("playmaker");
        return user;
    }
  • 运行结果
time filter init
...
...
...
time filter start
进入getInfo服务
time filter 11
time filter finish

在这里插入图片描述

  • 运行结果

在这里插入图片描述

  • 所有用户请求都用经过这个过滤器来处理
  • 开发的时候可能要用第三方框架的过滤器,第三方框架的过滤器是没法改代码的,没有申明Component注解,怎么加入进来?
  • 传统的方式就是去web.xml中配置,spring boot 没有这个配置文件的 但是可以通过配置类添加
@Configuration
public class WebConfig {

    //和去web.xml配置标签是一样的
    @Bean
    public FilterRegistrationBean timeFilter(){
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();

        TimeFilter timeFilter = new TimeFilter();
        registrationBean.setFilter(timeFilter);

        List<String> urls = new ArrayList<>();
        urls.add("/*");//可以指定filter在那些url中起作用
        registrationBean.setUrlPatterns(urls);

        return registrationBean;
    }
}
  • 删掉TimeFilter上的注解,测试
  • 效果一样的
time filter start
进入getInfo服务
time filter 262
time filter finish
  • 不过,存在一个问题
    在这里插入图片描述

  • 过滤器有一些限制,比如获取不到具体是哪个控制器哪一个方法处理的,只能拿到http的请求和响应

  • 过滤器是j2ee的规范,在拦截器之前,还没有进入我们的具体控制器方法的时候被调用

  • 想获取这些信息,就需要用拦截器

三.拦截器(interceptor)
  • 编写拦截器
@Component//光申明注解不行 需要额外配置
public class TimeInterceptor implements HandlerInterceptor {
    @Override//Controller方法调用前执行,比拦截器有优势,第三个参数
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");

        System.out.println(((HandlerMethod)handler).getBean().getClass().getName());//雷鸣
        System.out.println(((HandlerMethod)handler).getMethod().getName());//方法名

        //在filter中一个方法完成逻辑的,拦截器中是两个方法 只能用request来存储数据
        request.setAttribute("startTime",new Date().getTime());
        return true;//决定后面是否要执行 Controller中的方法
    }

    @Override//Controller方法处理后调用 Controller方法抛出异常就不会调用了
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
        long start = (long) request.getAttribute("startTime");
        System.out.println("time interceptor 耗时:"+(new Date().getTime()-start));
    }

    @Override//不管抛出异常没有 都会执行
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
        long start = (long) request.getAttribute("startTime");
        System.out.println("time interceptor 耗时:"+(new Date().getTime()-start));
        System.out.println("ex is "+ex);

    }
}
  • 添加配置
//org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter 5.0+已过时
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private TimeInterceptor timeInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {//拦截器注册器
            registry.addInterceptor(timeInterceptor); // 可以添加多个不同的拦截器
    }

    //和去web.xml配置标签是一样的
    @Bean
    public FilterRegistrationBean timeFilter(){
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();

        TimeFilter timeFilter = new TimeFilter();
        registrationBean.setFilter(timeFilter);

        List<String> urls = new ArrayList<>();
        urls.add("/*");//可以指定filter在那些url中起作用
        registrationBean.setUrlPatterns(urls);

        return registrationBean;
    }
}
  • 运行结果
time filter start
preHandle
com.playmaker.web.controller.UserController
getInfo
进入getInfo服务
postHandle
time interceptor 耗时:242
afterCompletion
time interceptor 耗时:242
ex is null
time filter 266
time filter finish
  • 假如这里抛出异常了
 @GetMapping(value = "/{id:\\d+}")
    @JsonView(User.UserDetailView.class)
    public User getInfo(@PathVariable(name = "id") String idxxx){
        throw new UserNotExistException(idxxx);
//        System.out.println("进入getInfo服务");
//        User user = new User();
//        user.setUsername("playmaker");
//        return user;
    }
time filter start
preHandle
com.playmaker.web.controller.UserController
getInfo
afterCompletion
time interceptor 耗时:139
ex is null
time filter 166
time filter finish
  • 这里抛异常,没有posthandler了
  • 但是异常仍然是空的,上次写的自定义异常处理器,把异常处理掉了,异常最终没有传递过来,自定义异常处理器是在afterCompletion之前执行的
  • 改成这样就可以了
    @GetMapping(value = "/{id:\\d+}")
    @JsonView(User.UserDetailView.class)
    public User getInfo(@PathVariable(name = "id") String idxxx){
        throw new RuntimeException("user not exist");
       // throw new UserNotExistException(idxxx);
//        System.out.println("进入getInfo服务");
//        User user = new User();
//        user.setUsername("playmaker");
//        return user;
    }

在这里插入图片描述
在这里插入图片描述

  • 这个是错误处理控制器
  • 拦截器会拦截所有控制器 Controller方法调用,不仅你自己写的,Spring提供的Controller方法也会被拦截
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值