JavaWeb世界(十三):过滤器和监听器

过滤器

概述

在 Java 中的最小程序单元是类,程序中的过滤器就是一个特殊的类。类似 Servlet 就是 Web 的一个组件。Filter 也是一个组件。

作用

过滤器处于客户端和服务端之间,可以对所有的请求或者响应做拦截操作。

  1. 以常规的方式调用资源(Servlet / JSP);
  2. 利用修改过的请求调用信息;
  3. 调用资源之后,但在响应到客户端之前,对响应做出修改;
  4. 阻止当前资源调用,转而调用其他资源。

在开发中的应用:

  1. 可以对请求中的字符做编码操作;
  2. 登录验证过滤器
  3. 敏感字过滤(非法文字过滤)
  4. 做 MVC 框架中的前端控制器(处理所有请求共同的操作,再分发)

开发中两个常用的思想:

  1. DRY原则:Don’t Repeat Yourself.
    开发中拒绝任何代码重复(重复代码不利于维护,以及性能较差)
  2. 责任分离原则: 每段代码只做自己最擅长的事情

在这里插入图片描述
Filter:
1.
当服务器启动时,便会执行 Filter 接口中的 init构造器方法

	public FilterDemo() {
		System.out.println("构造器");
	}

	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("init");
	}

在这里插入图片描述
FilterChain(过滤器链): 多个过滤器按照一定的顺序排列起来。
拦截器栈

当有多个过滤器时,按照 filter-mapping 的顺序进行拦截:

<filter>
		<filter-name>FilterDemo</filter-name>
		<filter-class>com.cherry._01_hello.FilterDemo</filter-class>
	</filter>
	<filter>
		<filter-name>FilterDemo2</filter-name>
		<filter-class>com.cherry._01_hello.FilterDemo2</filter-class>
	</filter>
	<filter>
		<filter-name>FilterDemo3</filter-name>
		<filter-class>com.cherry._01_hello.FilterDemo3</filter-class>
	</filter>
	
	
	<filter-mapping>
		<filter-name>FilterDemo2</filter-name>
		<url-pattern>/test.jsp</url-pattern>
	</filter-mapping>
	
	<filter-mapping>
		<filter-name>FilterDemo3</filter-name>
		<url-pattern>/test.jsp</url-pattern>
	</filter-mapping>
	<filter-mapping>
		<filter-name>FilterDemo</filter-name>
		<url-pattern>/test.jsp</url-pattern>
	</filter-mapping>

输出结果为:

FilterDemo2...before
FilterDemo3...before
FilterDemo1...before
FilterDemo1...after
FilterDemo3...after
FilterDemo2...after
<filter-mapping>
	<filter-name>FilterDemo</filter-name>
	<url-pattern> /* </url-pattern>
	<dispatcher>REQUEST</dispatcher>
</filter-mapping>

这里的 dispatcher 设置 REQUEST 会对于重定向的请求拦截。

<dispatcher>FORWARD</dispatcher>

这里的 dispatcher 设置 FORWARD 会对请求转发进行拦截。

<dispatcher>INCLUDE</dispatcher>

对请求包含做拦截

<dispatcher>ERROR</dispatcher>

跳转到错误页面做拦截
自己写一个404页面:

<error-page>
	<error-code>404</error-code>
	<location>/404.jsp</location>
</error-page>
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	404,请求的资源找不到
</body>
</html>

可以看到对错误页面的跳转也拦截了一次。

请求编码过滤器

<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>com.cherry._02_characterencoding.CharacterEncodingFilter</filter-class>
	<!-- 设置编码  -->
	<init-param>
		<param-name>encoding</param-name>
		<param-value>UTF-8</param-value>
	</init-param>
		
	<!-- 是否强制使用编码  -->
	<init-param>
		<param-name>force</param-name>
		<param-value>true</param-value>
	</init-param>
</filter>	

CharacterEncodingFilter.java:

package com.cherry._02_characterencoding;

import java.io.IOException;

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.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//字符编码过滤器
public class CharacterEncodingFilter implements Filter {

	private String encoding;
	private boolean forceEncoding = false;

	public void init(FilterConfig config) throws ServletException {
		this.encoding = config.getInitParameter("encoding");
		forceEncoding = Boolean.valueOf(config.getInitParameter("force"));
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		//类型转换
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;

		//设置编码
		//1.应用中没有编码并且自己设置了编码
		//2.应用中已经存在编码,但是依然使用自己设置的编码

		if (hasLength(encoding) && (req.getCharacterEncoding() == null || forceEncoding)) {
			req.setCharacterEncoding(encoding);
		}
		chain.doFilter(req, resp);
	}

	private boolean hasLength(String str) {
		return str != null && "".equals(str.trim());
	}
}

我们需要做判断:
如果自己设置了编码并且没有默认编码,则使用自己设定的编码;
如果自己设定了编码并且有默认编码,但是需要强制使用自己设定的编码,则使用自己设定的编码。
我们在配置文件中再加入一个参数 force,用来设定是否要强制使用自己设定的编码。

登录检查过滤器

概述
判断登录与否,需要在每一个页面都要添加类似于下面的代码:

<%
	Object obj = session.getAttribute("USER_IN_SESSION");
	if (obj == null) {
		response.sendRedirect("/login.jsp");
	}
%>

很是麻烦。通过过滤器可以很容易的解决这一问题。

CheckLoginFilter.java:

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//登录检查过滤器
public class CheckLoginFilter implements Filter {

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;
		
		Object obj = req.getSession().getAttribute("USER_IN_SESSION");
		//若没有登录
		if (obj == null) {
			resp.sendRedirect("/login.jsp");
			return;
		}
		chain.doFilter(req, resp);	
	}
}

但是这样浏览器会因为重定向次数过多(循环重定向)而崩溃:
在这里插入图片描述
很好理解,当请求的资源里没有登录信息时,会被过滤拦截,然后请求登录界面,然而登录界面是在请求 Servlet 时才有登录信息,而本身的登录界面一开始是没有登录信息的,因此又会被拦截,从而接着请求登录界面。。。
解决的话只要加上一个判断,判断当前请求的资源是否是登录界面:

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.mysql.cj.result.StringValueFactory;

//登录检查过滤器
public class CheckLoginFilter implements Filter {

	private static int cnt = 0;

	private String[] unCheckURIs = { "/login.jsp", "/login" };
	
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {

		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;
		String uri = req.getRequestURI();
		System.out.println("当前正在过滤的资源是:" + uri + " " + cnt++);
		if (!Arrays.asList(unCheckURIs).contains(uri)) {
			Object obj = req.getSession().getAttribute("USER_IN_SESSION");
			//若没有登录
			if (obj == null) {
				resp.sendRedirect("/login.jsp");
				return;
			}
		}
		chain.doFilter(req, resp);
	}
}

但是请求的资源不一定都是 /login.jsp 或者 /login,其中一个办法就是将不需要过滤的资源放在 web.xml 配置文件中,也可以新建一个 unCheckUris.xml 文件:

<init-param>
	<param-name>unCheckUris</param-name>
	<param-value>unCheckUris.xml</param-value>
</init-param>
<unCheckUris>
	<uri>/login.jsp</uri>
	<uri>/login</uri>
	...
</unCheckUris>

但是在网页中,图片资源等是不需要登录就可以访问,这样做依然很麻烦,我们可以转变思维,将需要过滤的资源放在一起,这样就方便多了。

敏感字过滤器

FilterUtil.java:

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * 敏感字过滤工具类
 */
public class FilterUtil {

	private static List<String> stopWords = new ArrayList<>();

	static {
		Scanner sc = new Scanner(
				Thread.currentThread().getContextClassLoader().getResourceAsStream("stopwords.txt"),
				"UTF-8");
		while (sc.hasNextLine()) {
			String line = sc.nextLine();
			if (CommonUtil.hasLength(line)) {
				stopWords.add(line);
			}
		}
		sc.close();
	}

	/**
	 * 执行过滤的方法
	 * @param msg
	 * @return
	 */
	public static String filter(String msg) {
		for (String str : stopWords) {
			if (msg.indexOf(str) >= 0) {
				msg = msg.replaceAll(str, buildMask(str, "*"));
			}
		}
		return msg;
	}

	private static String buildMask(String s, String mask) {
		StringBuilder sBuilder = new StringBuilder();
		for (int i = 0; i < s.length(); i++) {
			sBuilder.append(mask);
		}
		return sBuilder.toString();
	}
	
	public static void main(String[] args) {
		System.out.println(stopWords);
		System.out.println(filter("nmsl and nmslwccnm"));
	}
}

结果如下:
在这里插入图片描述
我们在请求是通过一个过滤器将敏感词汇变成 **,然后在 Servlet 中通过 req.getParameter 方法获得参数,但是存在一个问题,过滤后的内容如何传给 Servlet 呢?如果通过 req.setAttribute 的方法,就修改了本身获取参数的机制,不太合理。因此我们要重写实现了 HttpServletRequest 接口的实现类 HttpServletRequestWrapper 的父类 ServletRequestWrapper 中的 getParameter 方法,使得其实现过滤器的功能:
在这里插入图片描述

MessageRequestWrapper.java:

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import com.cherry.util.FilterUtil;

//敏感字过滤请求包装类
public class MessageRequestWrapper extends HttpServletRequestWrapper {

	public MessageRequestWrapper(HttpServletRequest request) {
		super(request);
	}

	/**
	 * 覆盖 getParameter, 使之支持敏感字过滤
	 */
	public String getParameter(String name) {
		if ("title".equals(name) || "content".equals(name)) {
			//返回过滤之后的 title和 content
			return FilterUtil.filter(super.getParameter(name));
		}
		return super.getParameter(name);
	}

}

然后新建一个过滤器 MessageFilter:

MessageFilter.java:

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
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;

import com.cherry._04_stopwords.request.MessageRequestWrapper;

/**
 * 敏感字监听器
 * @author Bryan
 *
 */
@WebFilter("/*")
public class MessageFilter implements Filter {

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		//把不具有处理敏感字的请求对象换成可以处理敏感字的请求对象
		HttpServletRequest req = (HttpServletRequest) request;

		//装饰模式,将具有敏感字过滤功能包装在请求中
		HttpServletRequest requestWrapper = new MessageRequestWrapper(req);

		chain.doFilter(requestWrapper, response);
	}
}

这里实际用到了一种包装设计模式,也叫装饰者模式,将一定功能包装在对象中,这里是将具有敏感字过滤功能的请求包装在原先的请求中。
敏感字过滤器

监听器

Web 中的监听器,主要用于监听作用域对象的创建,监听作用域对象属性的添加、删除、替换。

  1. 监听作用域对象的创建和销毁
    ServletRequestListener: 监听请求对象的创建和销毁
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package javax.servlet;

import java.util.EventListener;

/**
 * A ServletRequestListener can be implemented by the developer
 * interested in being notified of requests coming in and out of
 * scope in a web component. A request is defined as coming into
 * scope when it is about to enter the first servlet or filter
 * in each web application, as going out of scope when it exits
 * the last servlet or the first filter in the chain.
 *
 * @since Servlet 2.4
 */
public interface ServletRequestListener extends EventListener {

    /**
     * The request is about to go out of scope of the web application.
     * The default implementation is a NO-OP.
     * @param sre Information about the request
     */
    public default void requestDestroyed (ServletRequestEvent sre) {
    }

    /**
     * The request is about to come into scope of the web application.
     * The default implementation is a NO-OP.
     * @param sre Information about the request
     */
    public default void requestInitialized (ServletRequestEvent sre) {
    }
}

HttpSessionListener: 监听会话对象的创建和销毁

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package javax.servlet.http;

import java.util.EventListener;

/**
 * Implementations of this interface are notified of changes to the list of
 * active sessions in a web application. To receive notification events, the
 * implementation class must be configured in the deployment descriptor for the
 * web application.
 *
 * @see HttpSessionEvent
 * @since v 2.3
 */
public interface HttpSessionListener extends EventListener {

    /**
     * Notification that a session was created.
     * The default implementation is a NO-OP.
     *
     * @param se
     *            the notification event
     */
    public default void sessionCreated(HttpSessionEvent se) {
    }

    /**
     * Notification that a session is about to be invalidated.
     * The default implementation is a NO-OP.
     *
     * @param se
     *            the notification event
     */
    public default void sessionDestroyed(HttpSessionEvent se) {
    }
}

ServletContextListener: 监听上下文的创建和销毁 (Spring中会用到)

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package javax.servlet;

import java.util.EventListener;

/**
 * Implementations of this interface receive notifications about changes to the
 * servlet context of the web application they are part of. To receive
 * notification events, the implementation class must be configured in the
 * deployment descriptor for the web application.
 *
 * @see ServletContextEvent
 * @since v 2.3
 */

public interface ServletContextListener extends EventListener {

    /**
     ** Notification that the web application initialization process is starting.
     * All ServletContextListeners are notified of context initialization before
     * any filter or servlet in the web application is initialized.
     * The default implementation is a NO-OP.
     * @param sce Information about the ServletContext that was initialized
     */
    public default void contextInitialized(ServletContextEvent sce) {
    }

    /**
     ** Notification that the servlet context is about to be shut down. All
     * servlets and filters have been destroy()ed before any
     * ServletContextListeners are notified of context destruction.
     * The default implementation is a NO-OP.
     * @param sce Information about the ServletContext that was destroyed
     */
    public default void contextDestroyed(ServletContextEvent sce) {
    }
}

然后在 web.xml 中配置(一般在 web.xml 中先配 Listener,然后配 Filter,最后配 Servlet)

<listener>
	<listener-class>com.cherry._05_listener.ContextLoaderListener</listener-class>
</listener>

这里没有 mapping 标签的原因是因为:监听器要监听谁,就实现哪个接口就行了。
更简单的是知己打一个标签即可:
@WebListener
启动
销毁

Web 中的监听器组件没有初始化参数配置,如果要解决监听器中的编码,只能使用全局初始化参数

  1. 监听作用域对象的属性的添加、删除、替换

HttpSessionAttributeListener: 监听 session 作用域中属性的添加、删除和替换

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package javax.servlet.http;

import java.util.EventListener;

/**
 * This listener interface can be implemented in order to get notifications of
 * changes to the attribute lists of sessions within this web application.
 *
 * @since v 2.3
 */
public interface HttpSessionAttributeListener extends EventListener {

    /**
     * Notification that an attribute has been added to a session. Called after
     * the attribute is added.
     * The default implementation is a NO-OP.
     *
     * @param se Information about the added attribute
     */
    public default void attributeAdded(HttpSessionBindingEvent se) {
    }

    /**
     * Notification that an attribute has been removed from a session. Called
     * after the attribute is removed.
     * The default implementation is a NO-OP.
     *
     * @param se Information about the removed attribute
     */
    public default void attributeRemoved(HttpSessionBindingEvent se) {
    }

    /**
     * Notification that an attribute has been replaced in a session. Called
     * after the attribute is replaced.
     * The default implementation is a NO-OP.
     *
     * @param se Information about the replaced attribute
     */
    public default void attributeReplaced(HttpSessionBindingEvent se) {
    }
}

ServletRequestAttributeListener: 监听 request 作用域中属性的添加、删除和替换

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package javax.servlet;

import java.util.EventListener;

/**
 * A ServletRequestAttributeListener can be implemented by the
 * developer interested in being notified of request attribute
 * changes. Notifications will be generated while the request
 * is within the scope of the web application in which the listener
 * is registered. A request is defined as coming into scope when
 * it is about to enter the first servlet or filter in each web
 * application, as going out of scope when it exits the last servlet
 * or the first filter in the chain.
 *
 * @since Servlet 2.4
 */
public interface ServletRequestAttributeListener extends EventListener {
    /**
     * Notification that a new attribute was added to the
     * servlet request. Called after the attribute is added.
     * The default implementation is a NO-OP.
     * @param srae Information about the new request attribute
     */
    public default void attributeAdded(ServletRequestAttributeEvent srae) {
    }

    /**
     * Notification that an existing attribute has been removed from the
     * servlet request. Called after the attribute is removed.
     * The default implementation is a NO-OP.
     * @param srae Information about the removed request attribute
     */
    public default void attributeRemoved(ServletRequestAttributeEvent srae) {
    }

    /**
     * Notification that an attribute was replaced on the
     * servlet request. Called after the attribute is replaced.
     * The default implementation is a NO-OP.
     * @param srae Information about the replaced request attribute
     */
    public default void attributeReplaced(ServletRequestAttributeEvent srae) {
    }
}

ServletContextAttributeListener: 监听 application 作用域中属性的添加、删除和替换

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package javax.servlet;

import java.util.EventListener;

/**
 * Implementations of this interface receive notifications of changes to the
 * attribute list on the servlet context of a web application. To receive
 * notification events, the implementation class must be configured in the
 * deployment descriptor for the web application.
 *
 * @see ServletContextAttributeEvent
 * @since v 2.3
 */

public interface ServletContextAttributeListener extends EventListener {
    /**
     * Notification that a new attribute was added to the servlet context.
     * Called after the attribute is added.
     * The default implementation is a NO-OP.
     * @param scae Information about the new attribute
     */
    public default void attributeAdded(ServletContextAttributeEvent scae) {
    }

    /**
     * Notification that an existing attribute has been removed from the servlet
     * context. Called after the attribute is removed.
     * The default implementation is a NO-OP.
     * @param scae Information about the removed attribute
     */
    public default void attributeRemoved(ServletContextAttributeEvent scae) {
    }

    /**
     * Notification that an attribute on the servlet context has been replaced.
     * Called after the attribute is replaced.
     * The default implementation is a NO-OP.
     * @param scae Information about the replaced attribute
     */
    public default void attributeReplaced(ServletContextAttributeEvent scae) {
    }
}

在这里插入图片描述
HttpSessionAttributeListenerDemo:

@WebListener
public class HttpSessionAttributeListenerDemo implements HttpSessionAttributeListener {
	public void attributeAdded(HttpSessionBindingEvent se) {
		System.out.println("属性添加:" + se.getName() + "-" + se.getValue());
	}

	public void attributeRemoved(HttpSessionBindingEvent se) {
		System.out.println("属性删除:" + se.getName() + "-" + se.getValue());
	}

	public void attributeReplaced(HttpSessionBindingEvent se) {

		System.out.println("属性替换:" + se.getName() + "-" + se.getValue() + ","
				+ se.getSession().getAttribute(se.getName()));
	}

}
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<%
	session.setAttribute("name", "NAME");
	session.setAttribute("age", "AGE");
	session.removeAttribute("age");
	session.setAttribute("name", "My Name");
%>
<body>
	Hello World!
</body>
</html>

Result
值得注意的是,se.getValue() 得到的是之前的属性值,如果要得到修改过后的属性值,要重新获得当前 Session: se.getSession().getAttribute(se.getName())

监听器可以用在在线人数统计,当有人登录时,会监测到 session 会话建立。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值