在SpringBoot中添加Servlet、Filter、Listener

标签:

本文出自jvm123.com-java技术分享站:http://jvm123.com/2019/11/springboot-servlet-filter-listener.html

在普通的java web项目中,Servlet、Filter、Listener都可以通过在 web.xml 文件中配置的方式添加,但是在springboot项目中,没有web.xml文件,可以使用以下的方式添加:

添加servlet

  1. 继承父类HttpServlet,或者GenericServlet
  2. 在实现的servlet类上使用@WebServlet注解;
  3. 在配置类使用@ServletComponentScan 注解扫描servlet组件即可。
package com.jvm123.servlet

import javax.servlet.AsyncContext
import javax.servlet.ServletException
import javax.servlet.annotation.WebServlet
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

/**
 *
 * @author yawn http://jvm123.com
 *     2019/11/4 11:20
 */
@WebServlet(
        name = "testServlet",
        urlPatterns = "/servlet/test",
        asyncSupported = true
)
class TestServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        AsyncContext asyncContext = req.startAsync()
        asyncContext.start(new Runnable() {
            @Override
            void run() {
                doRequest(req, resp)
                asyncContext.complete()
            }
        })
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doRequest(req, resp)
    }

    private void doRequest(HttpServletRequest req, HttpServletResponse resp) {
        resp.getOutputStream().print("这是一个原生的 HttpServlet!")
    }
}

如果使用异步servlet,需要加上asyncSupported = true ,再使用AsyncContext来执行处理,执行完处理之后,要使用asyncContext.complete()来完成异步处理,否则会一直等待,直至超时。

上面代码中的doGet方法使用了异步的处理,doPost方法使用了同步处理。

Servlet的实现继承关系

servlet的实现继承关系如下,实现时,可以继承 HttpServlet ,重写其中的 doXXX() 方法,或者继承GenericServlet,实现其中的抽象方法service(ServletRequest req, ServletResponse res)

在SpringBoot中添加Servlet、Filter、Listener插图

添加filter

添加filter过滤器时,可以经过以下几个步骤:

  1. 实现接口javax.servlet.Filter
  2. 在实现的servlet类上使用@WebFilter注解;
  3. 在配置类使用@ServletComponentScan 注解扫描组件。
package com.jvm123.servlet

import org.slf4j.Logger
import org.slf4j.LoggerFactory

import javax.servlet.Filter
import javax.servlet.FilterChain
import javax.servlet.FilterConfig
import javax.servlet.ServletException
import javax.servlet.ServletRequest
import javax.servlet.ServletResponse
import javax.servlet.annotation.WebFilter
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

/**
 * @author yawn http://jvm123.com
 *     2019/11/3 14:36
 */
@WebFilter(urlPatterns = "/*")
class AuditFilter implements Filter {

    Logger logger = LoggerFactory.getLogger(AuditFilter.class)

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

    @Override
    void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest
        HttpServletResponse response = (HttpServletResponse) servletResponse
        String uri = request.getRequestURI()
        String referer = request.getHeader("Referer")
        String host = request.getHeader("Host")
        int statusCode = response.getStatus()
        filterChain.doFilter(servletRequest, servletResponse)
        logger.info("{} {}, host={}, referer={}", statusCode, uri, host, referer)
    }

    @Override
    void destroy() {
    }
}

添加listener

Listener的添加与上面类似,可以添加对不同servlet组件的监听,例如request、session、application,也可以监听其中属性的变化,分别实现不同的接口就可以实现这一目的。示例如下:

package com.jvm123.servlet

import javax.servlet.ServletRequestEvent
import javax.servlet.ServletRequestListener
import javax.servlet.annotation.WebListener
import javax.servlet.http.HttpServletRequest

/**
 *
 * @author yawn http://jvm123.com
 *     2019/11/4 11:42
 */
@WebListener
class RequestListener implements ServletRequestListener {

    @Override
    void requestDestroyed(ServletRequestEvent event) {
        HttpServletRequest request = (HttpServletRequest) event.getServletRequest()
        println "request被销毁:" + request.getRequestURL()
    }

    @Override
    void requestInitialized(ServletRequestEvent event) {
        HttpServletRequest request = (HttpServletRequest) event.getServletRequest()
        println "request初始化:" + request.getRequestURL()
    }
}

spring boot 加载servlet组件验证

在添加了以上servlet组件之后,我们可以通过检查springboot启动时的日志进行验证,每个组件如果在启动时被加载,就会有如下的日志输出:

DEBUG [main] o.s.b.web.servlet.ServletContextInitializerBeans 128 : Added existing Servlet initializer bean 'dispatcherServletRegistration'; order=2147483647, resource=class path resource [org/springframework/boot/autoconfigure/web/DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfiguration.class]
DEBUG [main] o.s.b.web.servlet.ServletContextInitializerBeans 128 : Added existing Filter initializer bean 'com.jvm123.servlet.AuditFilter'; order=2147483647, resource=null
DEBUG [main] o.s.b.web.servlet.ServletContextInitializerBeans 128 : Added existing EventListener initializer bean 'com.jvm123.servlet.RequestListener'; order=2147483647, resource=null
DEBUG [main] o.s.b.web.servlet.ServletContextInitializerBeans 128 : Added existing EventListener initializer bean 'com.jvm123.servlet.SessionListener'; order=2147483647, resource=null
DEBUG [main] o.s.b.web.servlet.ServletContextInitializerBeans 128 : Added existing Servlet initializer bean 'testServlet'; order=2147483647, resource=null
DEBUG [main] o.s.b.web.servlet.ServletContextInitializerBeans 176 : Created Filter initializer for bean 'characterEncodingFilter'; order=-2147483648, resource=class path resource [org/springframework/boot/autoconfigure/web/HttpEncodingAutoConfiguration.class]
INFO  [main] o.s.boot.web.servlet.ServletRegistrationBean 190 : Mapping servlet: 'dispatcherServlet' to [/]
INFO  [main] o.s.boot.web.servlet.ServletRegistrationBean 190 : Mapping servlet: 'testServlet' to [/servlet/test]
INFO  [main] o.s.boot.web.servlet.FilterRegistrationBean 251 : Mapping filter: 'characterEncodingFilter' to: [/*]
INFO  [main] o.s.boot.web.servlet.FilterRegistrationBean 262 : Mapping filter: 'com.jvm123.servlet.AuditFilter' to urls: [/*]

由日志可以看出,除了dispatcherServlet和characterEncodingFilter之外,其他的servlet组件都是我们自定义的。

发表评论