Springboot编写servlet、filter、listener

1.原理

Servlet 的三种方式。

1、实现 Servlet 接口

因为是实现 Servlet 接口,所以我们需要实现接口里的方法。

下面我们也说明了 Servlet 的执行过程,也就是 Servlet 的生命周期。

//Servlet的生命周期:从Servlet被创建到Servlet被销毁的过程
//一次创建,到处服务
//一个Servlet只会有一个对象,服务所有的请求
/*
 * 1.实例化(使用构造方法创建对象)
 * 2.初始化  执行init方法
 * 3.服务     执行service方法
 * 4.销毁    执行destroy方法
 */
public class ServletDemo1 implements Servlet {

    //public ServletDemo1(){}

     //生命周期方法:当Servlet第一次被创建对象时执行该方法,该方法在整个生命周期中只执行一次
    public void init(ServletConfig arg0) throws ServletException {
                System.out.println("=======init=========");
        }

    //生命周期方法:对客户端响应的方法,该方法会被执行多次,每次请求该servlet都会执行该方法
    public void service(ServletRequest arg0, ServletResponse arg1)
            throws ServletException, IOException {
        System.out.println("hehe");

    }

    //生命周期方法:当Servlet被销毁时执行该方法
    public void destroy() {
        System.out.println("******destroy**********");
    }
//当停止tomcat时也就销毁的servlet。
    public ServletConfig getServletConfig() {

        return null;
    }

    public String getServletInfo() {

        return null;
    }
}

2、继承 GenericServlet 类

它实现了 Servlet 接口除了 service 的方法,不过这种方法我们极少用。

public class ServletDemo2 extends GenericServlet {

    @Override
    public void service(ServletRequest arg0, ServletResponse arg1)
            throws ServletException, IOException {
        System.out.println("heihei");

    }
}

3、继承 HttpServlet 方法

public class ServletDemo3 extends HttpServlet {

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

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

}

Filter 过滤器方法

过滤器是一个实现了 javax.servlet.Filter 接口的 Java 类。javax.servlet.Filter 接口定义了三个方法:主要是实现这个接口

序号 方法 & 描述
1 public void doFilter (ServletRequest, ServletResponse, FilterChain)
该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain用户访问后续过滤器。
2 public void init(FilterConfig filterConfig)
web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。
3 public void destroy()
Servlet容器在销毁过滤器实例前调用该方法,在该方法中释放Servlet过滤器占用的资源。

过滤器链也就是chain.dofilter()的代码:类似这种相同匹配模式的过滤器会存在于同一个过滤链中,然后按照初始化的先后顺一次排列,实现逐层过滤。其中filterChain中有个doFilter方法,他的作用是将当前请求转发给过滤链中的下一个过滤器进行过滤,然后将过滤结果,只有等待下一个过滤器执行过滤完成后才能继续执行。该执行过程类似如下图:

  

  如上图,通过过滤链逐层执行过滤就像一层嵌套,一层套一层,如果过滤链中只有一个过滤器(或者执行到最后一个)的话,执行了chain.doFilter()他会直接将请求转发出去,获取request resource资源,因为从始至终都是同一个request和response在传递,所以每次过滤都可以修改请求或返回结果,实现了过滤修改的目的。

1.过滤器实例

package com.runoob.test;

//导入必需的 java 库
import javax.servlet.*;
import java.util.*;

//实现 Filter 类
public class LogFilter implements Filter  {
    public void  init(FilterConfig config) throws ServletException {
        // 获取初始化参数
        String site = config.getInitParameter("Site"); 

        // 输出初始化参数
        System.out.println("网站名称: " + site); 
    }
    public void  doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {

        // 输出站点名称
        System.out.println("站点网址:http://www.runoob.com");

        // 把请求传回过滤链
        chain.doFilter(request,response);
    }
    public void destroy( ){
        /* 在 Filter 实例被 Web 容器从服务移除之前调用 */
    }
}

2.过滤器直接返回

当过滤器满足条件的时候,不执行之后的过滤器和web请求的时候,可以不写chain.dofilter(),停止转发

过滤器中我们可以根据 doFilte() 方法中的 request 对象获取表单参数信息,例如我们可以获取到请求的用户名和密码进行逻辑处理,也可以通过 response 对用户做出回应。比如如果验证用户名不正确,禁止用户访问 web 资源,并且向浏览器输出提示,告诉用户用户名或者密码不正确等等;

public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {

    //获取请求信息(测试时可以通过get方式在URL中添加name)
    //http://localhost:8080/servlet_demo/helloword?name=123
    String name = req.getParameter("name");

    // 过滤器核心代码逻辑
    System.out.println("过滤器获取请求参数:"+name);
    System.out.println("第二个过滤器执行--网站名称:www.runoob.com");

    if("123".equals(name)){
        // 把请求传回过滤链
        chain.doFilter(req, resp);
    }else{
        //设置返回内容类型
        resp.setContentType("text/html;charset=GBK");

        //在页面输出响应信息
        PrintWriter out = resp.getWriter();
        out.print("<b>name不正确,请求被拦截,不能访问web资源</b>");
        System.out.println("name不正确,请求被拦截,不能访问web资源");
    }
}

大概看下web如何配置

​
<?xml version="1.0" encoding="UTF-8"?>  
<web-app>  
<filter>
  <filter-name>LogFilter</filter-name>
  <filter-class>com.runoob.test.LogFilter</filter-class>
  <init-param>
    <param-name>Site</param-name>
    <param-value>菜鸟教程</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>LogFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>  
  <!-- 类名 -->  
  <servlet-name>DisplayHeader</servlet-name>  
  <!-- 所在的包 -->  
  <servlet-class>com.runoob.test.DisplayHeader</servlet-class>  
</servlet>  
<servlet-mapping>  
  <servlet-name>DisplayHeader</servlet-name>  
  <!-- 访问的网址 -->  
  <url-pattern>/TomcatTest/DisplayHeader</url-pattern>  
</servlet-mapping>  
</web-app>  

​

 Listern监听器

1、什么是Java监听器

监听器也叫Listener,是Servlet的监听器,它可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量。

2、Listener接口分类

ServletContext监听器

1.1 ServletContextListener监听ServletContext对象,可以监听到容器的初始化和销毁

1.2 ServletContextAttributeListener监听对ServletContext属性的操作,比如增加、删除、修改(application范围)

HttpSession监听器

2.1> HttpSessionListener监听Session对象,包括了session的创建和销毁。

2.2> HttpSessionAttributeListener监听Session中的属性操作,比如增加、删除、修改(session范围)

2.3> HttpSessionActivationListener监听HTTP会话的active和passivate情况,passivate是指非活动的session被写入持久设备(比如硬盘),active相反。 
注意:HttpSessionActivationListener不需要web.xml配置文件

实现了HttpSessionActivationListener接口的 JavaBean 对象可以感知自己被活化和钝化的事件

活化:javabean对象和Session一起被反序列化(活化)到内存中(硬盘到内存);
钝化:javabean对象和Session一起序列化到硬盘中(内存到硬盘);
javabean对象存在Session中,当服务器把session序列化到硬盘上时,如果Session中的javabean对象实现了Serializable接口
那么服务器会把session中的javabean对象一起序列化到硬盘上,javabean对象和Session一起被序列化到硬盘中的这个操作称之为钝化
如果Session中的javabean对象没有实现Serializable接口,那么服务器会先把Session中没有实现Serializable接口的javabean对象移除
然后再把Session序列化(钝化)到硬盘中;

当绑定到 HttpSession对象中的javabean对象将要随 HttpSession对象被钝化之前,
web服务器调用该javabean对象的 sessionWillPassivate方法,
这样javabean对象就可以知道自己将要和 HttpSession对象一起被序列化(钝化)到硬盘中
当绑定到HttpSession对象中的javabean对象将要随 HttpSession对象被活化之后,
web服务器调用该javabean对象的sessionDidActive方法,
这样javabean对象就可以知道自己将要和 HttpSession对象一起被反序列化(活化)回到内存中 

2.4> HttpSessionBindingListener监听器:感知Session绑定的事件监听器 ,就是我们常常存储的数据
注意:HttpSessionBindingListener不需要web.xml配置文件

保存在Session域中的对象可以有多种状态:
(1)绑定(session.setAttribute("bean",Object))到Session中;
(2)从Session域中解除(session.removeAttribute("bean"))绑定;
(3)随Session对象持久化到一个存储设备中;
(4)随Session对象从一个存储设备中恢复;

Servlet 规范中定义了两个特殊的监听器接口"HttpSessionBindingListener和HttpSessionActivationListener"
来帮助JavaBean 对象了解自己在Session域中的这些状态: ,
实现这两个接口的类不需要 web.xml 文件中进行注册。

ServletRequest监听器

3.1> ServletRequestListener监听Request对象

3.2> ServletRequestAttributeListener监听Requset中的属性操作

3、Java代码

1.1> ServletContextListener 


监听器类代码:

public class ls implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("------------------"+"容器初始化");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("------------------"+"容器销毁");
    }
}

web.xml配置代码:

 <!-- ServletContext对象监听器 -->
    <listener>
        <listener-class>cn.itcast.erp.listener.servletContext.ServletContextListener1</listener-class>
    </listener>

1.2> ServletContextAttributeListener 
监听器类代码:

package com.xxx.listener;
 
import javax.servlet.ServletContext;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener;
 
@WebListener
public class MyServletContextAttributeListener implements ServletContextAttributeListener {
 
	//把一个属性存入application范围时触发该方法
	@Override
	public void attributeAdded(ServletContextAttributeEvent event) {
		ServletContext application=event.getServletContext();
		//获取添加的属性名和属性值
		String name=event.getName();
		Object value=event.getValue();
		System.out.println(application+"范围内添加了名为"+name+"值为"+value+"的属性");
		
	}
	
	//把一个属性从application范围删除时触发该方法
	@Override
	public void attributeRemoved(ServletContextAttributeEvent event) {
 
		ServletContext application=event.getServletContext();
		//获取被删除的属性名和属性值
		String name=event.getName();
		Object value=event.getValue();
		System.out.println(application+"范围内名为"+name+"值为"+value+"的属性被删除了");
		
	}
	
	//替换application范围内的属性时触发该方法
	@Override
	public void attributeReplaced(ServletContextAttributeEvent event) {
		ServletContext application=event.getServletContext();
		//获取被替换的属性名和属性值
		String name=event.getName();
		Object value=event.getValue();
		System.out.println(application+"范围内"+name+"值为"+value+"的属性被替换了");
				
	}
	
 
}

2.1>HttpSessionListener 
监听器类代码:

public class HttpSessionListener1 implements HttpSessionListener{
    /**
     * 通知会话已创建。
     * session创建之后调用
     */
    @Override
    public void sessionCreated(HttpSessionEvent event) {
        System.out.println("session创建之后");
        HttpSession session = event.getSession();
    }

    /**
     * 通知会话即将失效。
     * session销毁之前调用
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        System.out.println("session销毁之前");
        HttpSession session = event.getSession();
    }

}

web.xml配置代码:

    <!-- HttpSession对象监听器 -->
    <listener>
        <listener-class>cn.itcast.erp.listener.session.HttpSessionListener1</listener-class>
    </listener>

2.2> HttpSessionAttributeListener

监听器类代码:

public class HttpSessionAttributeListener1 implements HttpSessionAttributeListener{

    /**
     * 通知某个属性已被添加到会话中。 在添加属性后调用。
     */
    @Override
    public void attributeAdded(HttpSessionBindingEvent event) {
        System.out.println("session添加属性后调用");
        HttpSession session = event.getSession();
        String name = event.getName();
        Object value = event.getValue();
        System.out.println("被添加到session中的属性:" + "key=" + name + "   ,value=" + value);
    }

    /**
     * 通知某个属性已从会话中删除。 在属性被删除后调用。
     */
    @Override
    public void attributeRemoved(HttpSessionBindingEvent event) {
        System.out.println("session删除属性后调用");
        HttpSession session = event.getSession();
        String name = event.getName();
        Object value = event.getValue();
        System.out.println("被删除的session中的属性:" + "key=" + name + "   ,value=" + value);
    }

    /**
     * 在会话中通知属性已被替换。 在属性被替换后调用。
     */
    @Override
    public void attributeReplaced(HttpSessionBindingEvent event) {
        System.out.println("session替换属性后调用");
        HttpSession session = event.getSession();
        String name = event.getName();
        Object value = event.getValue();
        System.out.println("被替换的session中的属性:" + "key=" + name + "   ,替换之前的value=" + value);
    }

}

2.3> HttpSessionActivationListener 
监听器类代码(不需要配置web.xml):

public class HttpSessionActivationListener1 implements HttpSessionActivationListener {

    /**
     * 通知该会话即将被钝化。
     * 当前javaBean绑定到session中钝化之前
     */
    @Override
    public void sessionWillPassivate(HttpSessionEvent event) {
        System.out.println("session钝化之前");
        HttpSession session = event.getSession();
    }

    /**
     * 通知该会话刚刚被激活。
     * 当前javaBean绑定到session中活化之后
     */
    @Override
    public void sessionDidActivate(HttpSessionEvent event) {
        System.out.println("session活化之后");
        HttpSession session = event.getSession();
    }

}

2.4> HttpSessionBindingListener 
监听器类代码(不需要配置web.xml):

public class HttpSessionBindingListener1 implements HttpSessionBindingListener {

    /**
     * 通知对象它正在被绑定到会话并标识会话。(还未绑定)
     */
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println("当前对象正在绑定到session中,还未绑定");
        HttpSession session = event.getSession();

        String name = event.getName();
        Object value = event.getValue();
        System.out.println("将要被绑定到session中的key值:" + name + "value值:" + value);
        System.out.println("value值是否是当前对象:" + (value == this));//true

        Object valueNow = session.getAttribute(name);
        System.out.println("valueNow:" + valueNow);//null,还未绑定


    }

    /**
     * 通知对象它正在从会话中解除绑定并标识会话。(还未解除绑定)
     */
    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.out.println("当前对象它正在从会话中解除绑定");
        HttpSession session = event.getSession();

        String name = event.getName();
        Object value = event.getValue();
        System.out.println("将要解除绑定session中的key值:" + name + "value值:" + value);
        System.out.println("value值是否是当前对象:" + (value == this));//true

        Object valueNow = session.getAttribute(name);
        System.out.println("valueNow:" + valueNow);//null,还未解除绑定
    }

}

2.5还有

3.1> ServletRequestListener监听Request对象

3.2> ServletRequestAttributeListener监听Requset中的属性操作

方法与ServletContext类似,实现接口不同而已,不再描述。

2.内容

1.注册Servlet

(1)使用ServletRegistrationBean注册

  使用ServletRegistrationBean注册只需要在@Configuration类中加入即可,例如以下代码:

@Bean
	public ServletRegistrationBean myServlet() {
		ServletRegistrationBean myServlet = new ServletRegistrationBean();
		myServlet.addUrlMappings("/servlet");
		myServlet.setServlet(new MyServlet());
		return myServlet;
	}

 (2)使用@WebServlet

  使用@WebServlet注册,需要在Servlet类上使用该注解即可,但是需要在@Configuration类中使用Spring Boot提供的注解@ServletComponentScan扫描注册相应的Servlet。

2.注册Filter

(1)使用FilterRegistrationBean注册

  使用FilterRegistrationBean注册Filter,只需要在@Configuration类中加入即可,例如以下代码:

@Bean
	public FilterRegistrationBean myFilter() {
		FilterRegistrationBean myFilter = new FilterRegistrationBean();
		myFilter.addUrlPatterns("/*");
		myFilter.setFilter(new MyFilter());
		return myFilter;
	}

(2)使用@WebFilter

使用@WebFilter注册,需要在Filter类上使用该注解即可,但是需要在@Configuration类中使用Spring Boot提供的注解@ServletComponentScan扫描注册相应的Filter。

3.注册Listener

(1)使用ServletListenerRegistrationBean注册

  使用ServletListenerRegistrationBean注册Listener只需要在@Configuration类中加入即可,例如以下代码:

@Bean
	public ServletListenerRegistrationBean<MyListener> myServletListener() {
		ServletListenerRegistrationBean<MyListener> myListener = new ServletListenerRegistrationBean<MyListener>();
		myListener.setListener(new MyListener());
		return myListener;
	}

(2)使用@WebListener

  使用@WebListener注册,需要在Filter类上使用该注解即可,但是需要在@Configuration类中使用Spring Boot提供的注解@ServletComponentScan扫描注册相应的Listener。

3.总结

主要是web上的servlet、filter、listen,可以web配置、java配置、注解配置,而注解更加简单,不过记得要加入扫描器。监听器用处可以说较大,比如session的监听,可以做某些清楚工作。

转载资料:

http://www.runoob.com/servlet/servlet-writing-filters.html

http://www.runoob.com/servlet/servlet-intro.html

https://blog.csdn.net/menghuanzhiming/article/details/79042182

猜你喜欢

转载自blog.csdn.net/m0_37834471/article/details/81152812