当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能,如:在过滤器中解决乱码。
1、
Servlet
2、Filter
3、Listener
1、过滤器本身不是目标资源(不能直接被访问)
2、过滤器是再访问目标对象前后执行的,过滤器是双向的
3、过滤器可以配置多个
4、过滤器拦截的都是多个目标资源
一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤…
步骤:
1、定义一个类,实现接口Filter
2、实现方法
3、配置拦截路径
- web.xml
- 注解
配置版的代码演示
MyFilter.java
//创建java类 实现 javax.servlet.Filter接口 实现doFiLter方法
public class MyFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//request就是当前请求对象 所有的请求数据都包含在其中(注意 这时还是ServletRequest对象 不能使用HttpServletRequest对象方法)
//response就是对于本次请求的响应对象 (因为响应结束后还是通过过滤器返回 所以会创建)
//chain 过滤器链对象 代表是否继续执行 执行doFilter方法可以继续向下执行 否则到此中断
System.out.println("过滤器执行前");
// 放行 只有调用这个方法 对应的servlet才能继续执行
chain.doFilter(request, response);
System.out.println("过滤器执行后");
}
}
web.xml配置
<filter>
<filter-name>Demo1Filterfilter-name>
<filter-class>com.yh.Demo1Filterfilter-class>
filter>
<filter-mapping>
<filter-name>Demo1Filterfilter-name>
<url-pattern>/*url-pattern>
<url-pattern>/*url-pattern>
filter-mapping>
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/*")//访问所有资源之前,都会执行该过滤器
public class FilterDemo1 implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
System.out.println("FilterDemo1被执行了...");
//放行
chain.doFilter(request, response);
}
public void init(FilterConfig config) throws ServletException {
}
}
1、执行过滤器
2、执行放行后的资源
3、回来执行过滤器放行代码下边的代码
与srvelt相同,都是通过三个方法进行操作,不同的是Filter接口中init方法与destory方法为默认方法(可以不实现)。
init()
:在服务器启动后,会创建Filter对象,过滤器被创建后,立即调用init方法进行初始化。只执行一次。用于加载资源。doFilter()
:每一次请求被拦截资源时,会执行。执行多次。destroy()
:在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,过滤器实例被销毁之前,调用执行destroy()方法。只执行一次。用于释放资源。如果存在多个过滤器过滤相同的URL,根据xml配置顺序决定过滤器执行顺序。
执行的顺序与栈类似先进后出(先执行的过滤器 最后执行结束代码)。
FilterChain:代表的是过滤器链(多个过滤器组成在一起)。
用来放行,如果有下一个过滤器,执行下一个过滤器,若没有,则执行目标资源。
1、过滤器链是由Tomcat服务器提供的。
2、执行顺序是由filter-mapper顺序决定的。
@WebFilter("/*")
public class MyFilter1 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
System.out.println("myFilter1过滤器执行");
//FilterChain过滤器链
//该对象代码当前服务器所有的过滤器
//当当前过滤器执行后之后有其他过滤器时doFilter方法代表执行下一个过滤器的doFilter方法
//当当前过滤器执行之后没有其他过滤器时doFilter方法代表放行 执行请求的服务
//需要注意的,即使请求的服务器不存在 对应的过滤器也会执行(WEB-INF除外)
//如果是配置Filter 那么过滤器执行的顺序由配置mapping顺序决定
//如果使用注解配置,配置书写在类中,所以执行的顺序与文件顺序有关(相同url的过滤器 )
//注解形式就是在加载对应class之后根据calss中注解生成配置
//先加载的class会先生成配置,所以符合原本的mapping书写顺序
chain.doFilter(request, response);
System.out.println("myFilter1过滤器执行");
}
}
FilterConfig:过滤器配置对象,代表的是过滤器的配置信息,通过该接口中的一些方法来获取到当前的过滤器的配置文件信息。
方法名 | 功能 |
---|---|
getFilterName | 获取过滤器名字 |
getInitParameter(String name) | 获取过滤器中的初始化参数信息 |
getInitParamsterNames() | 获取过滤器中的所有初始化参数信息 |
getServletContext() | 获取ServletContext域对象 |
/**
* 每次拦截该方法都会执行了
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("demo2Filter执行了...");
// 放行
chain.doFilter(request, response);
}
/**
* 过滤器实例对象一被创建,立即调用Init方法做初始化
*/
public void init(FilterConfig config) throws ServletException {
// 先获取到过滤器配置文件中的的值
String filterName = config.getFilterName();
System.out.println("过滤器的名称:"+filterName);
// 可以获取到初始化参数
String username = config.getInitParameter("username");
String password = config.getInitParameter("password");
System.out.println(username+" : "+password);
// 获取初始化参数的名称
Enumeration<String> e = config.getInitParameterNames();
while(e.hasMoreElements()){
String key = e.nextElement();
String value = config.getInitParameter(key);
System.out.println(key+" : "+value);
}
// 获取到ServletContext对象(非常重要)
ServletContext context = config.getServletContext();
System.out.println("Demo2Filter已经被创建了...");
}
过滤器配置
<filter>
<filter-name>Demo2Filterfilter-name>
<filter-class>com.yh.Demo2Filterfilter-class>
<init-param>
<param-name>usernameparam-name>
<param-value>rootparam-value>
init-param>
<init-param>
<param-name>passwordparam-name>
<param-value>123456param-value>
init-param>
filter>
- 具体资源路径:
/index.jsp
只有访问index.jsp资源时,过滤器才会被执行。- 拦截目录:
/user/*
访问/user下的所有资源时,过滤器都会被执行。- 后缀名拦截:
*.jsp
访问所有后缀名为jsp资源时,过滤器都会被执行。- 拦截所有资源:
/*
访问所有资源时,过滤器都会被执行。
拦截方式配置:资源被访问的方式。
注解配置:
设置dispatcherTypes属性:
REQUEST
:默认值。浏览器直接请求资源FORWARD
:转发访问资源INCLUDE
:包含访问资源ERROR
:错误跳转资源ASYNC
:异步访问资源
web.xml配置:
设置
标签即可。
<filter>
<filter-name>Demo4Filterfilter-name>
<filter-class>com.yh.Demo4Filterfilter-class>
filter>
<filter-mapping>
<filter-name>Demo4Filterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
标签可以决定过滤器拦截哪些方式?
REQUEST
FORWARD
INCLUDE
ERROR
在使用jsp后响应数据的乱码基本不会出现,因为在jsp已经设置了各种的编码(由jsp请求发送的参数也很少乱码,但是依旧存在),解决中文乱码的方式是在servlet获取数据之前设置编码集合,但是每个servlet都设置编码集造成了代码的冗余,可以使用过滤器来解决这一问题,在所有servlet执行之前,通过过滤器设置请求与响应的编码集,这样通过过滤器的原理就可以只在过滤器书写一次,即可解决中文乱码问题。
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.HttpServletRequest;
@WebFilter("/*")
public class EncodingFilter implements Filter{
private String code = "UTF-8";
@Override
public void destroy() {
// TODO Auto-generated method stub
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding(code);
response.setCharacterEncoding(code);
response.setContentType("text/html;charset=" + code);
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
code = filterConfig.getInitParameter("code");
}
}
可以设置过滤器校验请求,必须在登录后再能继续请求对应的服务,如果没有登录跳转至登录页面,如果在每个服务doGet请求进行书写会造成代码的冗余,可以将登录验证操作书写在过滤器中,这样当请求时通过过滤器验证是否登录过,如果登录过继续请求对应的服务,如果没有登录过则跳转登录页面进行登录。
AutologinFilter.java
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.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* 自动登录的功能
* @author Administrator
*/
public class AutologinFilter implements Filter{
@Override
public void destroy() {
// TODO Auto-generated method stub
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
/**
* * 先从session中获取existUser的用户?返回两种结果
* 如果获取到了,说明session中已经存在该用户了,已经登录了。放行!!
* 如果没有获取到呢?目的:完成自动登录。获取指定名称的Cookie(目的:通过Cookie来获取到用户名和密码)
* 如果没有获取到Cookie。说明Cookie根本就没有!放行!!
* 如果获取到了Cookie,说明Cookie存在的,说明用户已经勾选了自动登录的功能!!
* 从Cookie中获取到用户名和密码,去数据库中查询
* 如果查询到的用户为null,说明用户名或者密码是错误的,(有可能被别人修改的)。不能让他自动登录的。放行!!
* 如果查询到了用户,说明Cookie中的用户名和密码是正确的,完成自动登录。
就把刚才查询出来的user保存到session中。放行!!
*/
// 从session获取用户
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession();
User user = (User) session.getAttribute("existUser");
// 如果user不为空,说明session中存在该用户的,放行
if(user != null){
chain.doFilter(req, response);
}else{
// 说明获取到的user是null的
Cookie[] cookies = req.getCookies();
// 获取指定名称的cookie
Cookie c = CookieUtil.getCookieByName(cookies, "autologin");
//如果c为null,说明用户没有选择过自动登录,不用做自动登录
if(c == null){
chain.doFilter(req, response);
}else{
// 说明c不为null,找到了cookie,从cookie获取用户名和密码
String value = c.getValue();
String username = value.split(",")[0];
String password = value.split(",")[1];
// 已经获取到了用户名和密码,去数据库查询一次
UserDao dao = new UserDao();
// 通过用户名和密码查询该用户
User existUser = dao.login(username, password);
// 如果返回的用户为null,说明用户名或者错误了
if(existUser == null){
// 放行
chain.doFilter(req, response);
}else{
// 用户已经存在了
session.setAttribute("existUser", existUser);
chain.doFilter(req, response);
}
}
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
LoginServlet.java
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = -38438478374394783L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
UserDao dao = new UserDao();
User existUser = dao.login(username, password);
// 如果用户范围null
if(existUser == null){
request.setAttribute("msg", "亲!用户名或者密码错误了!!");
request.getRequestDispatcher("/demo2/login.jsp").forward(request, response);
}else{
// 接收用户是否已经勾选了自动登录的复选框
String autoLogin = request.getParameter("auto_login");
// 如果和固定的值相同了,说明选中了
if("autoOK".equals(autoLogin)){
// 把用户名和密码拼接成字符串 aaa,aaa
String msg = existUser.getUsername()+","+existUser.getPassword();
// 证明勾选了,先把用户名和密码偷偷的保存起来
Cookie c = new Cookie("autologin", msg);
// 设置有效时间
c.setMaxAge(60*60);
// 设置有效路径
c.setPath("/");
// 会写cookie
response.addCookie(c);
}
// 成功了,把对象存入到session中
request.getSession().setAttribute("existUser", existUser);
response.sendRedirect(request.getContextPath()+"/demo2/home.jsp");
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
需求:
1、对day17_case案例录入的数据进行敏感词汇过滤
2、敏感词汇参考《敏感词汇.txt》
3、如果是敏感词汇,替换为 ***
分析:
1、对request对象进行增强。增强获取参数相关方法
2、放行。传递代理对象
增强对象的功能:
设计模式:一些通用的解决固定问题的方式
1、装饰模式
2、代理模式
- 概念:
1、真实对象:被代理的对象
2、代理对象:
3、代理模式:代理对象代理真实对象,达到增强真实对象功能的目的- 实现方式:
1、静态代理:有一个类文件描述代理模式
2、动态代理:在内存中形成代理类
- 实现步骤:
1、代理对象和真实对象实现相同的接口
2、代理对象 = Proxy.newProxyInstance();
3、使用代理对象调用方法。
4、增强方法
- 增强方式:
- 增强参数列表
- 增强返回值类型
- 增强方法体执行逻辑
代码实现:
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
/**
* 敏感词汇过滤器
*/
@WebFilter("/*")
public class SensitiveWordsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//1.创建代理对象,增强getParameter方法
ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强getParameter方法
//判断是否是getParameter方法
if(method.getName().equals("getParameter")){
//增强返回值
//获取返回值
String value = (String) method.invoke(req,args);
if(value != null){
for (String str : list) {
if(value.contains(str)){
value = value.replaceAll(str,"***");
}
}
}
return value;
}
//判断方法名是否是 getParameterMap
//判断方法名是否是 getParameterValue
return method.invoke(req,args);
}
});
//2.放行
chain.doFilter(proxy_req, resp);
}
private List<String> list = new ArrayList<String>();//敏感词汇集合
public void init(FilterConfig config) throws ServletException {
try{
//1.获取文件真实路径
ServletContext servletContext = config.getServletContext();
String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");
//2.读取文件
BufferedReader br = new BufferedReader(new FileReader(realPath));
//3.将文件的每一行数据添加到list中
String line = null;
while((line = br.readLine())!=null){
list.add(line);
}
br.close();
System.out.println(list);
}catch (Exception e){
e.printStackTrace();
}
}
public void destroy() {
}
}
需求:
- 请求该网站任意URL都算是对网站的请求,将请求进行保存到application域中,当每次服务器请求,经过过滤器时,都讲对应域中的数据取出+1并存入,在控制台打印。
- 创建过滤器类,配置过滤路径为/*,在doFilter()方法中书写代码,获取application指定key对应数据,如果为null则赋值1,否则加1后再次放入,书写统计servlet,请求servlet在页面打印当前服务器自启动访问的URL及其访问的次数。
代码实现:
VisitCountFilter.java
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
@WebFilter("/*")
public class VisitCountFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
ServletContext application = request.getServletContext();
Map<String, Integer> map = (Map<String, Integer>) application.getAttribute("map");
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
String url = httpServletRequest.getRequestURL().toString();
if (map.containsKey(url)) {
int num = map.get(url);
map.put(url, num + 1);
} else {
map.put(url, 1);
}
application.setAttribute("map", map);
chain.doFilter(request, response);
}
public void init(FilterConfig config) throws ServletException {
ServletContext application = config.getServletContext();
Map<String, Integer> map = new LinkedHashMap<String, Integer>();
application.setAttribute("map", map);
}
}
LoginServlet.java
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
ServletContext application = request.getServletContext();
Map<String, Integer> map = (Map<String, Integer>) application.getAttribute("map");
Set<String> keySet = map.keySet();
for (String string:keySet) {
response.getWriter().write(string +"==>"+ map.get(string) +"次");
}
}
}
监听器:是一个类,监听另一个java类的状态的改变。(商店报警装置,房间失火喷水装置)
- 由于是web端代码,所以只能监听web端应用对象(request/session/application)。
由于域对象添加方法与修改方法都是使用setAttribute(“key”,“value”)形式添加,所以在进行操作代码书写可能出现混淆,但是监听器不会混淆,监听器只会根据对应的事件执行对应的方法,只有当前对应的域对象中没有数据时调用setAttribute监听器才会执行对应的监听方法,如果已存在监听器之后执行的都是监听修改的方法(相同的key 监听器添加数据方法只执行一次),同理在删除对应数据时也一样,当对应域中不存在对应的key时,即使执行的对应的removeAttribute方法,监听器对应方法也不会执行。
ServletRequestListener
:监听request请求域对象的创建和销毁。MyRequestListener.java
//监听请求域对象的创建与销毁
//先实现接口,提供配置文件
public class MyRequestListener implements ServletRequestListener {
// 创建请求对象的监听方法
public void requestInitialized(ServletRequestEvent sre) {
// ServletRequestEvent代表请求事件对象
// 可以获取请求对象相应的数据
// 获取当前发生事件的请求对象
ServletRequest servletRequest = sre.getServletRequest();
// 之后可以通过请求对象获取请求域中相应的数据
System.out.println("请求对象创建");
}
// 销毁请求对象的监听方法
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("请求对象销毁");
}
}
web.xml配置监听器
<listener>
<listener-class>com.yh.listener.MyRequestListenerlistener-class>
listener>
ServletRequestAttributeListener
:监听request请求域对象中的数据。MyRequestAttrListener.java
//监听请求域对象中数据的操作
public class MyRequestAttrListener implements ServletRequestAttributeListener {
// 当调用setAttribute时添加新的数据时执行的方法
public void attributeAdded(ServletRequestAttributeEvent srae) {
// ServletRequestAttributeEvent 代表域对象值改变事件对象
// 可以从该对象中获取改变时域对象的值
// 获取对应的请求对象
ServletRequest servletRequest = srae.getServletRequest();
// 获取发生事件的key
String name = srae.getName();
// 获取发生事件的value
Object value = srae.getValue();
System.out.println("域对象添加数据:" + name + "=>" + value);
}
// 当调用removeAttribute删除数据时执行的方法
public void attributeRemoved(ServletRequestAttributeEvent srae) {
// 获取发生事件的key
String name = srae.getName();
// 获取发生事件的value
Object value = srae.getValue();
System.out.println("域对象删除数据:" + name + "=>" + value);
}
// 当调用setAttribute时修改已有数据时执行的方法
public void attributeReplaced(ServletRequestAttributeEvent srae) {
// 获取发生事件的key
String name = srae.getName();
// 获取发生事件的value
Object value = srae.getValue();
//修改获取的是修改前的数据
System.out.println("域对象修改数据:" + name + "=>" + value);
//修改后的数据可以通过获取请求对象之后获取对应的key
ServletRequest servletRequest = srae.getServletRequest();
System.out.println("修改后");
System.out.println("域对象修改数据:" + name + "=>" + servletRequest.getAttribute(name));
}
}
web.xml配置监听器
<listener>
<listener-class>com.yunhe.listener.MyRequestAttrListenerlistener-class>
listener>
ServletContextListener
:监听应用于对象的创建与销毁ServletContextAttributeListener
:监听域对象中数据的创建、修改、删除。MyApplicationListener.java
//ServletContextListener 监听应用于对象的创建与销毁
//ServletContextAttributeListener 监听域对象中数据的创建 修改 删除
public class MyApplicationListener implements ServletContextListener, ServletContextAttributeListener {
// 当服务器创建时执行
public void contextInitialized(ServletContextEvent sce) {
// ServletContextEvent 代表发生事件的对象
// 可以由该获取域对象 继续操作获取域对象中数据
ServletContext servletContext = sce.getServletContext();
System.out.println("应用域对象创建");
}
// 当服务器正常关闭时时执行
public void contextDestroyed(ServletContextEvent sce) {
// 注意:应用域对象随服务器的启动与关闭创建与销毁
System.out.println("应用域对象销毁");
}
// 监听域对象数据的添加
public void attributeAdded(ServletContextAttributeEvent scae) {
// ServletContextAttributeEvent 代表发生事件的对象
// 获取key
String name = scae.getName();
// 获取value
Object value = scae.getValue();
System.out.println("应用域对象存值:" + name + "=>" + value);
}
// 监听域对象数据的修改
public void attributeReplaced(ServletContextAttributeEvent scae) {
// 获取key
String name = scae.getName();
// 获取value
Object value = scae.getValue();
Object newValue = scae.getServletContext().getAttribute(name);
System.out.println("应用域对象修改数据:将"+name+" "+value+"=>"+newValue);
}
// 监听域对象数据的删除
public void attributeRemoved(ServletContextAttributeEvent scae) {
// 获取key
String name = scae.getName();
// 获取value
Object value = scae.getValue();
System.out.println("应用域对象删除数据:"+name+"=>"+value);
}
}
web.xml配置监听器
<listener>
<listener-class>com.yunhe.listener.MyApplicationListenerlistener-class>
listener>
HttpSessionListener
:监听session会话域对象的创建与销毁HttpSessionAttributeListener
:监听session会话域对象中数据的操作。MySessionListener.java
//@WebListener注解形式创建listener对象 在加载类时会自定进行监听器的配置
//HttpSessionListener session对象创建销毁监听器接口
//HttpSessionAttributeListener session对象值操作监听器接口
@WebListener
public class MySessionListener implements HttpSessionListener, HttpSessionAttributeListener {
//HttpSessionListener 提供的监听session创建的方法
@Override
public void sessionCreated(HttpSessionEvent se) {
//HttpSessionEvent 代表发生事件时的对象 可以获取相应的信息
HttpSession session = se.getSession();
System.out.println("session创建:"+session.getId());
}
//HttpSessionListener 提供的监听session销毁的方法
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
System.out.println("session销毁:"+session.getId());
}
//HttpSessionAttributeListener 提供监听session对象添加新的数据时执行
@Override
public void attributeAdded(HttpSessionBindingEvent sbe) {
//HttpSessionBindingEvent 代表监听对象
//获取添加数据的key
String name = sbe.getName();
//获取添加数据的value
Object value = sbe.getValue();
System.out.println("session添加数据:"+name+"=>"+value);
}
//HttpSessionAttributeListener 提供监听session对象修改数据时执行
@Override
public void attributeReplaced(HttpSessionBindingEvent sbe) {
//获取session对象
HttpSession session = sbe.getSession();
//获取添加数据的key
String name = sbe.getName();
//获取添加数据的value
Object value = sbe.getValue();
Object newValue = session.getAttribute(name);
System.out.println("session修改数据:"+name+" "+value+"=>"+newValue);
}
HttpSessionAttributeListener 提供监听在session对象删除数据时执行
@Override
public void attributeRemoved(HttpSessionBindingEvent sbe) {
//获取添加数据的key
String name = sbe.getName();
//获取添加数据的value
Object value = sbe.getValue();
System.out.println("session删除数据:"+name+"=>"+value);
}
}
概述
监听器:是监听HttpSession域对象的,操作的都是JavaBean,在web.xml中不需要进行配置(编写JavaBean类实现监听器接口)。
- 因为session域对象存储数据为Object,所以是可以存储自定义对象的,有时我们需要知道session在什么时候绑定了对象,就可以使用指定的对象实现HttpSessionBindingListener接口完成需求。
JavaBean类实现HttpSessionBindingListener
接口
//创建session域对象要保存对象 并实现HttpSessionBindingListener接口
public class User implements HttpSessionBindingListener {
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
//当当前类的对象被session绑定时 执行的方法
@Override
public void valueBound(HttpSessionBindingEvent event) {
// HttpSessionBindingEvent 发生事件的事件对象
//获取绑定时的key
String name = event.getName();
//获取绑定时的value
Object value = event.getValue();
System.out.println("session绑定了User对象:"+name+"=>"+value);
}
//当当前类的对象被session解绑时 执行的方法
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
String name = event.getName();
Object value = event.getValue();
System.out.println("session解绑了User对象:"+name+"=>"+value);
}
}
概述:
session对象存储在服务器中,但是当服务关闭时可能还存在很多没有到达过期时间的session对象,导致session没有到达过期时间就会被删除,tomcat容器提供了钝化与活化方法解决这一问题。
- session钝化:通过序列化的方式将session对象以及存储的数据转存到硬盘中。
- session活化:当服务器启动时,通过反序列化将session对象读取到内存中。
JavaBean类实现HttpSessionActivationListener
接口
同样需要将session存储的对象实现对应的监听方法,为了完成钝化与活化要求对象实现序列化接口。
/**
* 目的:完成钝化和活化
* 钝化是序列化到磁盘上(实现Serializable接口)
*
* @author Administrator
*/
public class User2 implements Serializable,HttpSessionActivationListener{
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
/**
* 活化
*/
public void sessionDidActivate(HttpSessionEvent arg0) {
System.out.println("User2被活化了...");
}
/**
* 钝化
*/
public void sessionWillPassivate(HttpSessionEvent arg0) {
System.out.println("User2被钝化了...");
}
}
对session机制的优化。
<Context>
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="D://yunhe"/>
Manager>
Context>
钝化后会使用sessionid作为文件名进行保存,只有在服务器再次启动,客户端再次请求时服务器获取sessionid之后进行活化。
需求:
使用监听器完成 在线人数的展示。
- 创建session监听器以及jsp页面
- 当请求jsp页面时 jsp页面展示当前session对象个数
- 在jsp页面书写按钮 点击按钮删除当前会话
代码演示:
count.html
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>counttitle>
head>
<body>
当前在线人数【${count}】人
<button>
<a href="quit">安全退出a>
button>
body>
html>
QuitServlet.java
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/quitServlet")
public class QuitServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
request.getSession().invalidate();
response.getWriter().write("退出成功");
}
}
CountListener.java
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class CountListener implements HttpSessionListener {
private int count = 0;
public void sessionCreated(HttpSessionEvent se) {
// 该方法主要执行就说明有session会话创建
count++;
//获取会话对象存入
HttpSession session = se.getSession();
session.setAttribute("count", count);
}
public void sessionDestroyed(HttpSessionEvent se) {
// 该方法主要执行就说明有session会话创建
count--;
//获取会话对象存入
HttpSession session = se.getSession();
session.setAttribute("count", count);
}
}
每日一点点进步
不进则退