spring boot Method for Setting Filter Listener and Interceptor

  • 2021-07-13 05:25:58
  • OfStack

Preface

In fact, this article is not springboot, we can also use it directly in spring ordinary projects

Setting Filters:

Previously, we used to configure filter in web. xml in ordinary projects, but only after servlet 3.0, we can set up filter directly in the project, because she provided a annotation @ WebFilter (under javax. servlet. annotation package). Using this annotation, we can set up filter, and also solve the embarrassment that we use springboot project without web. xml. The usage method is as follows


@WebFilter(urlPatterns="/*",filterName="corsFilter", asyncSupported = true)
public class CorsFilter implements Filter{

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

 }

 @Override
 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
   FilterChain chain) throws IOException, ServletException {
  HttpServletResponse response = (HttpServletResponse)servletResponse; 
  HttpServletRequest request = (HttpServletRequest)servletRequest;
  chain.doFilter(servletRequest, servletResponse);
 }

 @Override
 public void destroy() {

 }

}

In fact, there are 1 attribute that we need to set in WebFilter annotation. For example, value and urlPatterns, both of which have the same function, are all for setting the interception path. asyncSupported is to set whether the configured filter supports asynchronous response, which is not supported by default. If our project needs asynchronous response to the request and the request passes through filter, the asyncSupported attribute of this filter must be set to true otherwise an exception will be reported when requesting.

Set up the interceptor:

Write a configuration class that inherits org. springframework. web. servlet. config. annotation. WebMvcConfigurerAdapter or org. springframework. web. servlet. config. annotation. WebMvcConfigurationSupport and overrides the addInterceptors (InterceptorRegistry registry) method, in fact, the parent class's addInterceptors (InterceptorRegistry registry) method is an empty method. The usage method is as follows:


@Configuration
public class MvcConfig extends WebMvcConfigurationSupport {

 @Override
 public void addInterceptors(InterceptorRegistry registry) {
  InterceptorRegistration registration = registry.addInterceptor(new HandlerInterceptor() {
   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    return true;
   }

   @Override
   public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

   }

   @Override
   public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

   }
  });
  //  Configure the interception path 
  registration.addPathPatterns("/**");
  //  Configure paths that are not intercepted 
  registration.excludePathPatterns("/static/**");
 }
}

Configure the listener:

Generally, we commonly use javax. servlet. ServletRequestListener at request level and javax. servlet. http. HttpSessionListener at session level. Take ServletRequestListener as an example, write a class to implement ServletRequestListener interface and implement requestInitialized (ServletRequestEvent event) method and requestDestroyed (ServletRequestEvent event) method, and add @ WebListener (javax. servlet package) to the implementation class as follows


@WebListener
public class RequestListener implements ServletRequestListener {

 @Override
 public void requestDestroyed(ServletRequestEvent sre) {
  System.out.println(" End of request ");
 }

 @Override
 public void requestInitialized(ServletRequestEvent sre) {
  System.out.println(" Request start ");
 }
}

In this way, every request will be monitored. Before the request is processed, the equestInitialized (ServletRequestEvent event) method is called, and after the request is finished, the requestDestroyed (ServletRequestEvent event) method is called. In fact, there is a very good example in spring, that is, org. springframework. web. context. request. RequestContextListener class


public class RequestContextListener implements ServletRequestListener {

  private static final String REQUEST_ATTRIBUTES_ATTRIBUTE =
      RequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES";


  @Override
  public void requestInitialized(ServletRequestEvent requestEvent) {
    if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
      throw new IllegalArgumentException(
          "Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
    }
    HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
    ServletRequestAttributes attributes = new ServletRequestAttributes(request);
    request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
    LocaleContextHolder.setLocale(request.getLocale());
    RequestContextHolder.setRequestAttributes(attributes);
  }

  @Override
  public void requestDestroyed(ServletRequestEvent requestEvent) {
    ServletRequestAttributes attributes = null;
    Object reqAttr = requestEvent.getServletRequest().getAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE);
    if (reqAttr instanceof ServletRequestAttributes) {
      attributes = (ServletRequestAttributes) reqAttr;
    }
    RequestAttributes threadAttributes = RequestContextHolder.getRequestAttributes();
    if (threadAttributes != null) {
      // We're assumably within the original request thread...
      LocaleContextHolder.resetLocaleContext();
      RequestContextHolder.resetRequestAttributes();
      if (attributes == null && threadAttributes instanceof ServletRequestAttributes) {
        attributes = (ServletRequestAttributes) threadAttributes;
      }
    }
    if (attributes != null) {
      attributes.requestCompleted();
    }
  }

}

In this class, spring encapsulates every request once before starting, and sets up an threadLocal, In this way, we can get the request object through this threadLocal anywhere in the request processing. Of course, there are some benefits. For example, when we need request in the service layer, we don't need the caller to pass the request object to us. We can get it through a tool class. Isn't it beautiful?

Extension: We can add 1 ApplicationListener listener to the startup class of springboot, such as:


@SpringBootApplication
public class DemoApplication {

  public static void main(String[] args) {
    SpringApplication application = new SpringApplication(DemoApplication.class);
    application.addListeners(new ApplicationListener<ApplicationEvent>() {
      @Override
      public void onApplicationEvent(ApplicationEvent event) {
        System.err.println(event.toString());
      }
    });
    application.run(args);
  }
}

ApplicationEvent is an abstract class, There are many subclasses such as ServletRequestHandledEvent (triggered when a request event occurs), ApplicationStartedEvent (triggered before the application starts, do some startup preparation work), ContextRefreshedEvent (triggered after container initialization). There are many others, which will not be discussed here, but these ApplicationListener will only take effect when the springboot project is started by main method, that is to say, it is only applicable when the project needs to be packaged with jar. If the war package is packaged, it will have no effect in web containers such as Tomcat.

Summarize


Related articles: