spring boot-servlet、filter、listener

今天我们就来学习一下在spring boot中如何使用自定义的servlet、filter、listener。
在现在的web应用开始中,通常我们只需要对外发布restful的风格接口即可完成大部分业务需求,不再像传统的J2EE一样将页面以及逻辑统统卸载servlet当中。看似我们只需要填写正确的路径即可访问我们想要的接口方法,这其中也是由spring的DispatcherServlet进行调度的,那么我们自己如何实现自己的servlet,filter以及listener呢?接下来讲解一下如何实现。

在这里还不了解servlet,filter以及listener的可以先看一下我的另外一篇博客:
http://blog.csdn.net/wujiaqi0921/article/details/78196744

在spring boot中添加自己的Servlet、filter以及listener有两种方法,一种是代码注册,另一种是自动注册。
一、代码注册通过ServletRegistrationBean、 FilterRegistrationBean 和 ServletListenerRegistrationBean 获得控制,也可以通过实现 ServletContextInitializer 接口直接注册。

二、在 SpringBootApplication 上使用@ServletComponentScan 注解后,Servlet、Filter、Listener 可以直接通过 @WebServlet、@WebFilter、@WebListener 注解自动注册,无需其他代码。

在这里我们讲解一下如何通过自动注册来实现自己的SFL(Servlet、filter、listener)

servlet

首先是我们的TestServlet.java类

@WebServlet(name = "myServlet", urlPatterns = "/myServlet/*", loadOnStartup = 0)
public class TestServlet extends HttpServlet {

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("------------doPost()-----------");
        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>Hello Servlet</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>Hello Servlet</h1>");
        out.println("</body>");
        out.println("</html>");
    }

    @Override
    public void destroy() {
        System.out.print("-----------销毁----------");
    }

    @Override
    public void init() throws ServletException {
        System.out.print("-----------初始化----------");
    }
}

通过日志我们可以看到我们在访问自己的servlet时,首先进行初始化,接着调用我们的get方法。
———–初始化———-2017-10-11 14:30:50.141 INFO 793 — [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-10-11 14:30:50.148 INFO 793 — [ main] c.g.AresApplication : Started AresApplication in 6.778 seconds (JVM running for 8.336)
———-doGet()———
————doPost()———–

注意一点,我们需要在我们的启动类上加上@ServletComponentScan,开启servlet扫描。

@SpringBootApplication() 
@MapperScan(value = "com.god.dao") 
@ServletComponentScan
public class AresApplication {


    public static void main(String[] args) {
        SpringApplication.run(AresApplication.class, args);
    }
}

这样我们就能在访问http://localhost:8080/myServlet/xxx时看到hello servlet输出了。

这里需要注意一下几点:

  • name=”myServlet”不指定name的情况下,name默认是类全路径,即com.god.servlet.TestServlet
  • urlPatterns = “”为需要拦截的内容
  • loadOnStartup = 0 指在项目启动的时候加载
  • 注意若另一个servlet使用了相同的urlPatterns,则根据loadOnStartup大小判断访问路径,如另外一个otherServlet的loadOnStartup为1,则会访问otherServlet,当然,urlPatterns会优先进行精确匹配,这几点可以看上一章中servlet与filter等关系中了解。

Filter

这里直接上代码,我们定义了一个TestFilter过滤器,命名为myFilter,过滤所有的url请求,并开启异步处理。

@WebFilter(filterName = "myFilter", urlPatterns = "/*", asyncSupported = true)
public class TestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("-----------过滤器初始化-----------");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
        String uri = httpServletRequest.getRequestURI();
        if (!uri.contains("myServlet")) {
            httpServletResponse.sendRedirect(httpServletRequest.getRequestURI() + "/myServlet/filter");
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        System.out.println("-----------过滤器销毁-----------");
    }
}

在这里我们获取访问请求中的url地址,判断是否包含myServlet路径,若没有则加上/myServlet/filter,同时我对之前myServlet路径做了修改,在前面加上了test。这样,我们在访问http://localhost:8080/test时就会跳转到http://localhost:8080/test/myServlet/filter从而你就能在界面上看到Hello Servlet啦。如果细心一点你就会发现filter的初始化优先于servlet。看日志:

2017-10-11 15:09:40.010  INFO 824 --- [ost-startStop-1] o.s.b.w.s.ServletRegistrationBean        : Mapping servlet: 'myServlet' to [/test/myServlet/*]
-----------过滤器初始化-----------
2017-10-11 15:09:41.728  INFO 824 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1eb6749b: startup date [Wed Oct 11 15:09:36 CST 2017]; root of context hierarchy
2017-10-11 15:09:41.856  INFO 824 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-10-11 15:09:41.858  INFO 824 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-10-11 15:09:41.904  INFO 824 --- [           main] o.s.w.s.h.SimpleUrlHandlerMapping        : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-10-11 15:09:41.904  INFO 824 --- [           main] o.s.w.s.h.SimpleUrlHandlerMapping        : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-10-11 15:09:42.009  INFO 824 --- [           main] o.s.w.s.h.SimpleUrlHandlerMapping        : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-10-11 15:09:42.606  INFO 824 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
-----------初始化----------2017-10-11 15:09:42.716  INFO 824 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)

Listener

从上一篇博文我们可以了解到listener有包括:ServletContextListener、ServletContextAttributeListener 、HttpSessionListner、HttpSessionAttributeListener、HttpSessionBindingListener、 HttpSessionActivationListener、ServletRequestListner、ServletRequestAttributeListener 多种类型,在这里我们使用HttpSessionListner进行演示。

首先我们在之前的doFilter代码中加上

HttpSession httpSession = httpServletRequest.getSession();
httpSession.setMaxInactiveInterval(5);//设置session过期时间

接着,我们创建我们的TestListener类,这里面使用了读写锁,具体的大家可以自己去了解一下。

@WebListener(value = "myListener")
public class TestListener implements HttpSessionListener{


    private static int count = 0;
    ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();


    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        ServletContext servletContext = httpSessionEvent.getSession().getServletContext();
        String countStr = servletContext.getAttribute("onlineCount").toString();
        reentrantReadWriteLock.writeLock().lock();
        if (null != countStr && "" != countStr) {
            count = Integer.parseInt(countStr);
        }
        count++;
        reentrantReadWriteLock.writeLock().unlock();
        reentrantReadWriteLock.readLock().lock();
        servletContext.setAttribute("onlneCount", count);
        System.out.println("在线人数: " + count);
        reentrantReadWriteLock.readLock().unlock();
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        ServletContext servletContext = httpSessionEvent.getSession().getServletContext();
        reentrantReadWriteLock.writeLock().lock();
        count--;
        reentrantReadWriteLock.writeLock().unlock();
        reentrantReadWriteLock.readLock().lock();
        servletContext.setAttribute("onlineCount", count);
        System.out.println("在线人数: " + count);
        reentrantReadWriteLock.readLock().unlock();
    }
}

当我们浏览器访问时,会创建session,sessionListener会监听到session创建从而执行sessionCreated方法,对count计数加1,而session销毁时则会执行sessionDestroyed方法对count计数减1。

以上就是spring boot中通过自动注册实现SFL的方式,下面我们来看下如果通过代码注入的方式实现。直接上代码

/**
     * servlet注册
     * @return
     */
    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        return new ServletRegistrationBean(new TestServlet(), "/test/myServlet/*");
    }

通过查看ServletRegistrationBean可以知道第一个参数是我们servlet类,第二个参数是需要拦截的路径,可以使多路径。这样就能够访问我们的servlet啦!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值