SpringBoot2.x(六)拦截器实战和Servlet3.0自定义Filter、Listener

SpringBoot过滤器

从springboot启动日志中我们可以发现springboot默认加载的过滤器:

2018-07-19 18:43:32.748  INFO 9332 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-07-19 18:43:32.748  INFO 9332 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-07-19 18:43:32.748  INFO 9332 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2018-07-19 18:43:32.748  INFO 9332 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]

这四个过滤器位于 spring-boot.jar中的 org.springframework.boot.web.servlet.filter包下。


Ordered

他们都实现了 org.springframework.core.Ordered接口,通过其中的 int getOrder()对过滤器的优先级进行排序。


值得注意的是:Higher values are interpreted as lower priority(返回的int值越高意味着优先级越低,处理被拦截请求的顺序越靠后)。不要试图将两个过滤器返回相同的值,那样会导致排序失败。

Servlet3.0配置过滤器


1. 创建自定义过滤器类 MyFilter,实现 Filter接口中的方法 

 

  1. init()给过滤器初始化一些变量
  2. doFilter()编写拦截、放行逻辑
  3. destroy()多用来释放资源


2.  给 MyFilter加上 @WebFilter(serlvet3.0提供)注解以注册到servlet容器中,并通过 urlPatterns属性指定拦截路径 
urlPatterns指明拦截的路径


filterName,给过滤器命名,名称随意但最好不要重复

package top.zhenganwen.springbootweb.filter;

import org.apache.catalina.servlet4preview.http.HttpServletRequest;

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

@WebFilter(urlPatterns = "/hello/*",filterName = "myFilter")
public class MyFilter implements Filter {

    /**
     * 在servlet容器启动时被调用
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyFilter被加载了");
    }

    /**
     * 请求被拦截时被调用
     * @param request
     * @param response
     * @param chain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        System.out.println("请求的接口是:" + req.getRequestURL());
        System.out.println("经过了MyFilter................");
        //放行必须调用doFilter,拦截可以通过response重定向到提示页面(非前后端分离场景)
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

 

3.  给启动类加上 @ServletComponentScan注解以扫描 servlet组件

@SpringBootApplication
@ServletComponentScan
public class Application{
   public static void main(String[] args){
      SpringApplication.run(Application.class, args);
   }
}


4.   访问 localhost:8080/hello/hello

@RestController
@RequestMapping("/hello")
public class HelloWorldController {
    @RequestMapping("/hello")
    public String hello() {
        return "Hello World";
    }
}


5.   控制台输出
 

请求的接口是:http://localhost:8080/hello/hello
经过了MyFilter................

Servlet3.0的注解自定义原生Servlet实战

1.   创建自定义Servlet类 如UserServlet,继承 HttpServlet并重写 doGet和 doPost方法

2.   在 UserServlet上添加 @WebServlet注解并通过 urlPatterns属性配置请求路径,该注解在 Servlet3.0之后提供

package top.zhenganwen.springbootweb.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "userServlet",urlPatterns = "/user/hello")
public class UserServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.getWriter().write("hello");
        resp.getWriter().flush();
        resp.getWriter().close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}


3.   在启动类上添加 @ServletComponentScan注解
4.   访问 localhost:8080/user/hello,页面响应 hello

Servlet3.0的注解自定义原生Listener实战

常用的监听器接口有 ServletContextListener、ServletRequestListener、ServletSessionListener,分别监听容器、请求、会话的创建和销毁。还有 ServletContextAttributeListener、ServletRequestAttributeListener、ServletSessionAttributeListener对应监听三者的 addAttribute和 removeAttribute方法。


1.    创建自定义监听器类如 MyListener,按需实现上述6个接口中的一个
2.    在 MyListener上添加 @WebListener

package top.zhenganwen.springbootweb.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "userServlet",urlPatterns = "/user/hello")
public class UserServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.getWriter().write("hello");
        resp.getWriter().flush();
        resp.getWriter().close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}


3.    在启动类上添加 @ServletComponentScan注解
4.    访问 localhost:8080/hello/hello

@RequestMapping("/hello")
public String hello() {
    System.out.println("经过HelloWorldController");
    return "Hello World";
}
request initialized============
请求的接口是:http://localhost:8080/hello/hello
经过了MyFilter................
经过HelloWorldController
request destroyed===============


ServletContextListener主要用来做资源加载如加载缓存,ServletRequestListener则主要用来对请求进行统计

自定义拦截器及新旧配置对比


自定义拦截器


preHandle、postHandle、afterCompletion的调用时机已在相应的方法体中输出。

package top.zhenganwen.springbootweb.interceptor;

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

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

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("在调用controller之前============");
        //return true表示放行,将走到下一个拦截器或controller中
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("在调用controller之后、返回逻辑视图之前=======");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("在返回逻辑试图之后,通常用来释放资源=========");
    }
}


SpringBoot1.x配置拦截器


SpringBoot2.x与SpringBoot1.x配置拦截器的方式略有不同
1.    创建一个配置类继承 WebMvcConfigurerAdapter并实现其中的 addInterceptors,将自定义的拦截器加入到拦截器列表中
2.    在配置类上添加 @Configuration注解

package top.zhenganwen.springbootweb.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import top.zhenganwen.springbootweb.interceptor.LoginInterceptor;

@Configuration
public class CustomOldWebMvcInterceptor extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/cart/*/**");
        super.addInterceptors(registry);
    }
}


SpringBoot2.x配置拦截器


创建一个配置类实现 WebMvcConfigurer接口并重写 addInterceptors方法,在该配置类上添加 @Configuration注解

package top.zhenganwen.springbootweb.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import top.zhenganwen.springbootweb.interceptor.LoginInterceptor;

@Configuration
public class CustomWebMvcConfigure implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/cart/*/**");
        WebMvcConfigurer.super.addInterceptors(registry);
    }
}


值得注意的是,在 Java8中,接口中的方法是可以有方法体的,并且可以被 defautl修饰作为方法的默认实现。


测试


添加 CartController

package top.zhenganwen.springbootweb.controller;

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

@RestController
@RequestMapping("cart")
public class CartController {

    @RequestMapping("addItem")
    public Object addItem() {
        System.out.println("添加商品到购物车");
        return "success";
    }
}

 

访问 http://localhost:8080/cart/addItem ,控制台输出如下:

在调用controller之前============
添加商品到购物车
在调用controller之后、返回逻辑视图之前=======
在返回逻辑试图之后,通常用来释放资源=========


注意:不要试图启用新旧两种配置方式。


拦截器不生效的常见原因


1.    没有在配置类上添加 @Configuration,这样你的配置类不会生效,配置类中将自定义拦截器添加到拦截器列表的操作自然也不会生效。或者配置类不在启动类扫描范围之内
2.    请求路径与addPathPattern()的拦截规则不匹配。拦截所有目录应该用 /*/,末尾一定要写成 /**。*表示匹配当前目录的子目录,**表示匹配当前目录下的所有目录

拦截器和过滤器的区别

 

  • Filter是基于函数回调: doFilter(),而Interceptor则是基于AOP思想
  • Filter在只在Servlet前起作用,而Interceptor够深入到方法前后、异常抛出前后等
  • 依赖于Servlet容器即web应用中,而Interceptor不依赖于Servlet容器所以可以运行在多种环境。在接口调用的生命周期里,Interceptor可以被多次调用,而Filter只能在容器初始化时调用一次。
  • Filter和Interceptor的执行顺序:过滤前->拦截前->action执行->拦截后->过滤后


更多学习资料请点击白玉搜一搜搜索下载

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值