Listener监听器
javaweb开发中的监听器,用于监听web常见对象
HttpServletRequest、HttpSession、ServletContext(三个域对象)
的创建与销毁、属性变化、session绑定javaBean的。
监听机制
1.事件:就是一个事情
2.事件源:产生这个事件的源头
3.监听器:用于监听指定事件的对象
4.注册监听:监听器要想可以监听到事件的产生,必须进行注册。
常见监听器
监听 | 域对象创建与销毁 | 域对象的属性变化 |
ServletContext | ServletContextListener | ServletContextAttributeListener |
HttpSession | HttpSessionListener | HttpSessionAttributeListener |
HttpServletRequest | ServletRequestListener | ServletRequestAttributeListener |
监听session绑定javaBean | HttpSessionBindingListener 用于监听JavaBean对象是否绑定到session域 | HttpSessionActivationListener 用于监听javaBean对象的活化与钝化(序列化文件的消失与生成) |
关于域对象创建和销毁的监听接口只有两个方法:
...Created(...)监听创建的方法
...Destroyed(...)监听销毁的方法
关于域对象属性变化的监听接口只有三个方法:
attributeAdded(...)监听属性添加的方法
attributeRemoved(...)监听属性移除的方法
attributeReplaced(...)监听属性替换的方法
监听器快速入门
创建一个监听器的步骤
1.创建一个类实现指定的监听器接口
2.重写接口中的方法
3.在web.xml文件中对监听器进行注册
域对象创建销毁代码演示:
package com.aloha.listenerTest;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class Test1 implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext对象创建了");
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext对象销毁了");
}
}
<!-- 在web.xml文件中对监听器注册 -->
<listener>
<listener-class>com.aloha.listenerTest.Test1</listener-class>
</listener>
打开服务时
关闭服务时
Session的监听存在于:开启session时,第一次访问页面时session创建。关闭服务器,30分钟内不使用、session调用invalidate()方法、设置最大存活时间setMaxInactiveInterval(int interval)可以使session销毁。这里不做session的演示了。
ServletRequest的监听存在于:Servlet中的service()方法一执行,就创建了;service()方法执行完毕,就销毁了。JSP也是Servlet。
域对象属性变化演示:
package com.aloha.listenerTest;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
public class Test2 implements ServletRequestAttributeListener{
public void attributeAdded(ServletRequestAttributeEvent srae) {
System.out.println("ServletRequest添加属性了");
}
public void attributeRemoved(ServletRequestAttributeEvent srae) {
System.out.println("ServletRequest删除属性了");
}
public void attributeReplaced(ServletRequestAttributeEvent srae) {
System.out.println("ServletRequest替换属性了");
System.out.println(srae.getName()+" "+srae.getValue());
}
}
<listener>
<listener-class>com.aloha.listenerTest.Test2</listener-class>
</listener>
jsp中代码片段:
<body>
<%
request.setAttribute("tom", "cat");
request.setAttribute("tom", "miaomiaomiao");
request.removeAttribute("tom");
%>
</body>
一个定时销毁Session的Demo(部分代码):
代码实现功能:间隔两秒后,开始每隔5秒执行一次任务,任务内容是如果session存活时间超过5秒,则销毁session并将session从集合中移除。适用于秒杀类网页功能,可以节省session。
package com.aloha.test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSession;
public class Mscl implements ServletContextListener{
public void contextInitialized(ServletContextEvent sce) {
//通过事件源对象得到事件源(ServletContext)
ServletContext application = sce.getServletContext();
//创建一个集合用于存储所有session对象
// final List<HttpSession> list = new ArrayList<HttpSession>();//线程不安全,并发修改异常
final List<HttpSession> list = Collections.synchronizedList( new ArrayList<HttpSession>());
//把集合放到application中
application.setAttribute("sessions", list);
//创建一个计时器对象
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {//遍历集合
System.out.println("开始扫描了。。。");
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
HttpSession session = (HttpSession) iterator.next();
long l = System.currentTimeMillis() - session.getLastAccessedTime();
if(l>5000){
System.out.println("session移除了"+session.getId());
session.invalidate();
// list.remove(session);
iterator.remove();
}
}
/* 这种遍历方法不能进行运算修改!
* for (HttpSession session : list) {//匿名内部类必须得是final类型变量
long l = System.currentTimeMillis() - session.getLastAccessedTime();
if(l>5000){
session.invalidate();
list.remove(session);
}
}*/
}
}, 2000, 5000);//延迟两秒后间隔5秒执行一次
//再在web.xml中注册
}
public void contextDestroyed(ServletContextEvent sce) {
}
}
package com.aloha.test;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class Msl implements HttpSessionListener{
public void sessionCreated(HttpSessionEvent se) {
//通过时间元对象获取session对象
HttpSession session = se.getSession();
//通过session对象获取Servlet应用对象
ServletContext application = session.getServletContext();
//通过应用对象获取session并将session对象放到list集合中
List<HttpSession> list = (List<HttpSession>) application.getAttribute("sessions");
list.add(session);
System.out.println("添加了"+session.getId());
}
public void sessionDestroyed(HttpSessionEvent se) {
}
}
Filter过滤器
对于图书管理系统,我们就可以使用Filter来区分登陆者是管理员还是普通用户。
Filter的位置?如果我们添加了过滤器,那么浏览器每次发请求的时候都会先将请求发给过滤器,过滤器也是servlet,过滤器通过我们规定的过滤,将过滤后的内容发送给服务器。服务器给浏览器的响应也是如此,响应的时候会对数据进行压缩。
Filter对象要在web.xml中配置,可以做验证操作,起过滤拦截的作用。
javaweb中过滤器可以拦截所有访问web资源的请求或响应操作。
Filter步骤
1.创建一个类实现Filter接口。
2.该类中实现Filter接口中的doFilter()方法。
3.在web.xml文件中加入过滤器的注册。
注意:在实现类中的doFilter(...)方法中我们需要使用chain.doFilter(request,response) 方法放行,否则资源无法被访问到。
Filter生命周期
服务器启动时会创建Filter对象,并调用init方法,只调用一次;
当访问资源时,路径与拦截路径匹配,则执行Filter中的doFilter方法;
服务器关闭时,调用Filter中的destroy方法进行销毁操作。
其实和Servlet生命周期相同。
FilterConfig
方法摘要 | |
---|---|
String | getFilterName() Returns the filter-name of this filter as defined in the deployment descriptor. |
String | getInitParameter(String name) Returns a String containing the value of the named initialization parameter, or null if the parameter does not exist. |
Enumeration | getInitParameterNames() Returns the names of the filter's initialization parameters as an Enumeration of String objects, or an empty Enumeration if the filter has no initialization parameters. |
ServletContext | getServletContext() Returns a reference to the ServletContext in which the caller is executing. |
1.<url-pattern>
完全匹配 以”/demo1”开始,不包含通配符*
目录匹配 以”/”开始 以*结束 所有资源 /*
扩展名匹配 *.xxx 不能写成/*.xxx
2.<servlet-name>
它是对指定的servlet名称的servlet进行拦截的。
3.<dispatcher>
可以取的值有 REQUEST FORWARD ERROR INCLUDE
它的作用是:当以什么方式去访问web资源时,进行拦截操作.
1.REQUEST 当是从浏览器直接访问资源,或是重定向到某个资源时进行拦截方式配置的 它也是默认值
2.FORWARD 它描述的是请求转发的拦截方式配置
3.ERROR 如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
4.INCLUDE 如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用
自动登录案例
创建表
USE jdbctest;
SELECT DATABASE();
CREATE TABLE usera(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(100),
PASSWORD VARCHAR(100)
);
INSERT INTO usera VALUES(NULL,'tom','123');
全局过滤解决乱码问题
对于post方法提交的表单,可以使用下面的过滤器实现编码过滤:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
req.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
}
对于get方法提交的表单,这种方法是无效的,解决办法是:1.不要写get(哈哈哈,开玩笑)2.使用装饰者模式:
写一个装饰者类提供iso-8859-1到UTF-8的转换功能:
public class MyRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
public MyRequest(HttpServletRequest request) {
super(request);
this.request = request ;
}
@Override
public String getParameter(String name) {
name = request.getParameter(name);
try {
return new String(name.getBytes("iso-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
}
装饰:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
req = new MyRequest(req);
chain.doFilter(req, response);
}
装饰着使用Map集合,对多个标签处理(部分代码):
@Override
public String getParameter(String name) {
Map<String, String[]> map = getParameterMap();
return map.get(name)[0];
}
@Override
public String[] getParameterValues(String name) {
Map<String, String[]> map = getParameterMap();
return map.get(name);
}
private boolean flag = true;
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> map = request.getParameterMap();// 乱码
if (flag) {
for (Map.Entry<String, String[]> m : map.entrySet()) {
String[] values = m.getValue();
for (int i = 0; i < values.length; i++) {
try {
values[i] = new String(
values[i].getBytes("iso-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
flag = false;
}
return map;
}