Filter & Listener
一 监听器的概述
监听器就是一个实现了特定接口的Java类,用于监听另一个Java类的方法调用或属性的改变。当被监听对象发生上述事件后,监听器某个方法将会立即被执行。
即用来监听其他对象的变化,主要应用在图形化界面开发上。
事件源 专门产生事件的组件
事件 由事件源所产生的动作或者事情
监听器 专门处理事件源所产生的事件
注册/绑定监听器 让监听器时刻监听事件源是否有指定事件产生,如果产生指定事件,则调用监听器处理
在Servlet中定义了多种类型的监听器,用于监听ServletContext、HttpSession和ServletRequest这三个域对象。
分类
一类:监听三个域对象的创建和销毁(三个)
二类:监听三个域对象的属性变更(属性添加、移除、替换)(三个)
三类:监听HttpSession中JavaBean的状态改变(钝化、活化、绑定、解除绑定)(两个)
二 简单监听器使用演示
public class MyFrame extends JFrame {
public static void main(String args[]){
//1 创建事件源
MyFrame myFrame = new MyFrame();
myFrame.setBounds(300, 200, 500, 200);
myFrame.setVisible(true);
//3 绑定监听器
myFrame.addWindowListener(new MyWindowListener());
}
}
//2 创建监听器
class MyWindowListener implements WindowListener{
@Override
public void windowOpened(WindowEvent e) {
System.out.println("窗口打开...");
}
@Override
public void windowClosing(WindowEvent e) {
System.out.println("窗口关闭...");
//关闭虚拟机
System.exit(0);
}
@Override
public void windowClosed(WindowEvent e) {
}
@Override
public void windowIconified(WindowEvent e) {
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowActivated(WindowEvent e) {
}
@Override
public void windowDeactivated(WindowEvent e) {
}
}
三 ServletContextListener监听器的使用
1 在web项目中编写事件源
public class MyServletContextListener implements ServletContextListener{
@Override
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("ServletContext销毁了");
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("ServletContext创建了");
}
}
2 在web.xml中配置监听器
<listener>
<listener-class>com.my.listener.MyServletContextListener</listener-class>
</listener>
ServletContextListener企业用途
1 加载框架的配置文件:Spring框架提供了一个核心监听器ContextLoaderListener。
2 定时任务调度
四 HttpSessionListener监听器的使用
HttpSession创建和销毁
创建:服务器端第一次调用getSession()方法时候
销毁:
非正常关闭服务器(正常关闭服务器session会被序列化)
Session过期(默认过期时间30分钟)
手动调用session.invalidate()方法
访问HTML是否创建Session :不会
访问JSP是否创建Session :会
访问Servlet是否创建Session:不会(默认没有调用getSession方法)
public class MyHttpSessionListener implements HttpSessionListener{
@Override
public void sessionCreated(HttpSessionEvent arg0) {
System.out.println("HttpSession被创建了...");
}
@Override
public void sessionDestroyed(HttpSessionEvent arg0) {
System.out.println("HttpSession被销毁了...");
}
}
<listener>
<listener-class>com.my.listener.MyHttpSessionListener</listener-class>
</listener>
五 ServletRequestListener监听器的使用
ServletRequest对象的创建和销毁
创建:客户端向服务器发送一次请求,服务器就会创建request对象
销毁:服务器对这次请求作出了响应后,request对象就销毁了
访问HTML页面是否创建请求对象 :会
访问JSP页面是否创建请求对象 :会
访问Servlet是否创建请求对象 :会
public class MyServletRequestListener implements ServletRequestListener{
@Override
public void requestDestroyed(ServletRequestEvent arg0) {
System.out.println("ServletRequest创建了...");
}
@Override
public void requestInitialized(ServletRequestEvent arg0) {
System.out.println("ServletRequest销毁了...");
}
}
监听器的web.xml配置:略,参考上面
六 监听器的应用案例:统计当前在线人数
创建事件源,web.xml中配置监听器,制作jsp页面,开启服务器,访问jsp页面
public class MyServletContextListener implements ServletContextListener{
@Override
public void contextDestroyed(ServletContextEvent context) {
System.out.println("ServletContext销毁了");
}
@Override
public void contextInitialized(ServletContextEvent context) {
System.out.println("ServletContext创建了");
//服务器启动时初始化一个count存入ServletContext
context.getServletContext().setAttribute("count", 0);
}
}
public class MyHttpSessionListener implements HttpSessionListener{
@Override
public void sessionCreated(HttpSessionEvent newSession) {
//上线人数+1
HttpSession httpSession = newSession.getSession();
System.out.println(httpSession.getId() + "上线了...");
Integer count = (Integer) httpSession.getServletContext().getAttribute("count");
count++;
httpSession.getServletContext().setAttribute("count", count);
}
@Override
public void sessionDestroyed(HttpSessionEvent newSession) {
//下1线人数-1
HttpSession httpSession = newSession.getSession();
System.out.println(httpSession.getId() + "下线了...");
Integer count = (Integer) httpSession.getServletContext().getAttribute("count");
count--;
httpSession.getServletContext().setAttribute("count", count);
}
}
<listener>
<listener-class>com.my.listener.MyServletContextListener</listener-class>
</listener>
<listener>
<listener-class>com.my.listener.MyHttpSessionListener</listener-class>
</listener>
<session-config>
<session-timeout>1</session-timeout>
</session-config>
session-timeout单位:分钟
<body>
在线人数:${count}
</body>
七 监听三个域对象属性变更的监听器
(Attribute:属性)
ServletContextAttributeListener 监听ServletContext对象中的属性变更(属性添加,替换,移除)
HttpSessionAttributeListener 监听HttpSession对象中的属性变更(属性添加,替换,移除)
ServletRequestAttributeListener 监听ServletRequest对象中的属性变更(属性添加,替换,移除)
监听器的编写:
public class MyHttpSessionAttributeLitener implements HttpSessionAttributeListener{
@Override
public void attributeAdded(HttpSessionBindingEvent arg0) {
System.out.println("向session中添加了属性...");
}
@Override
public void attributeRemoved(HttpSessionBindingEvent arg0) {
System.out.println("从session中移除了属性...");
}
@Override
public void attributeReplaced(HttpSessionBindingEvent arg0) {
System.out.println("从session中替换了属性...");
}
}
web.xml中监听器的配置:略
jsp测试页面:
<body>
<%
session.setAttribute("name", "user1");//添加属性
session.setAttribute("name", "user2");//替换属性
session.removeAttribute("name");//移除属性
%>
</body>
八 监听HttpSession中Java类状态改变的监听器
保存在Session域中的Java类可以有多种状态:
1 绑定到session中
2 从session中解除绑定
3 随session对象持久化到一个存储设备中(钝化)
4 随session对象从一个存储设备中恢复(活化)
Servlet对方中定义了两个特殊的监听的接口来帮助Java类了解自己在Session域中的状态:
HttpSessionBindingListener接口 监听Java类在HttpSession中绑定和解除绑定的状态
HttpSessionActivationListener接口 监听HttpSession中Java类的钝化和活化
实现这两个接口的类不需要在web.xml中进行配置
用途:当访问页面的用户过多,创建的session对象过多,占用内存资源,此时可以设置session活跃时间,超过时间无活动的session可以持久化到硬盘中,节省内存资源
使用演示:
1 创建bean对象,提供set/get方法,实现HttpSessionBindingListener/HttpSessionActivationListener接口
2 在jsp中<% new一个bean对象,setName,再将bean对象set到session中%>,访问页面,即完成了bean对象的绑定
3 让bean对象实现序列化接口Serializable,此时访问jsp页面后,关闭服务器,session对象即被序列化到tomcat本地文件夹下,再次启动服务器,即被反序列化到session中
配置session的序列化和反序列化:context.xml
配置位置:
tomcat/conf/context.xml 所有tomcat下虚拟主机和虚拟目录下的工程都会序列化session
tomcat/conf/Catalina/localhost/context.xml localhost虚拟主机下的所有项目会序列化session
工程/META-INF/context.xml 当前工程才会序列化session
<Context>
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="路径"/>
</Manager>
</Context>
maxIdleSwap:Session不活动的最长时间,超过该时间,Session Manager 将会把该Session对象转移到Session Store中,该Session将不在内存中。1 代表1分钟
九 Filter概述
Filter即过滤器,过滤客户端向服务器发送的请求,是Servlet技术中最实用的技术,通过Filter技术,对web服务器所管理的资源(JSP,Servlet,静态图片或静态html文件)进行拦截,从而实现一些特殊的功能。
使用:
1 编写一个类实现Filter接口
2 在web.xml中对过滤器进行配置
public class FilterDemo1 implements Filter{
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("过滤器执行了...");
//放行
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
<filter>
<filter-name>FilterDemo1</filter-name>
<filter-class>com.my.filter.FilterDemo1</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterDemo1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
/* 代表全部拦截
十 FilterChain对象概述
FilterChain过滤器链:在一个web应用中,可以编写多个Filter,这些Filter组合起来称为是一个过滤器链
Web服务器根据Filter在web.xml文件中的注册顺序(mapping的配置顺序)依次调用过滤器
十一 Filter的生命周期
Filter的创建和销毁由web服务器负责。Web应用程序启动的时候,web服务器创建Filter的实例对象,并调用其init方法进行初始化(filter对象只会创建一次,init方法也只会执行一次)。
每次filter进行拦截的时候,都会执行doFilter的方法。
当服务器关闭,或应用从服务器中移除时,服务器会销毁Filter对象。
十二 FilterConfig对象概述
在Filter的init方法中有一个参数FilterConfig,FilterConfig对象作用是获取Filter的相关配置信息:
1.获取初始化参数
String getInitparameter(String name);
Enumeration EnumerngetInitParameterNames();
2.获取Filter的名称: getFilterName();
3.获取ServletContext对象:getServletContext();
十三 过滤器的相关配置
<url-pattern>的配置
完全路径匹配 :以/开始 比如/aaa /aaa/bbb
目录匹配 : 以/开始 以*结束 比如/* /aaa/* /aaa/bbb/*
扩展名匹配 : 以*开始 比如*.jsp *.do *.action
<servlet-name>的配置
根据Servlet的配置名称拦截Servlet。
<dispatcher>的配置
默认的情况下过滤器会拦截请求。如果进行转发(需要拦截这次转发)。
dispatcher的取值
REQUEST :默认值。过滤器默认拦截的就是请求。
FORWARD:转发。
INCLUDE :页面包含的时候进行拦截
ERROR :页面出现全局错误页面跳转的时候进行拦截
<filter-mapping>
<filter-name>FilterDemo1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
此时过滤器将会拦截全部页面访问请求。因为这里没有制定任何的< dispatcher >元素,默认值是REQUEST。
<filter-mapping>
<filter-name>FilterDemo1</filter-name>
<filter-class>com.my.filter.FilterDemo1</filter-class>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
此时只要是通过<jsp:include page="xxx.jsp" />,嵌入进来的页面,每嵌入的一个页面,都会走一次指定的过滤器
<filter-mapping>
<filter-name>FilterDemo1</filter-name>
<filter-class>com.my.filter.FilterDemo1</filter-class>
<dispatcher>FOWARD</dispatcher>
</filter-mapping>
此时只有从别的页面转发到当前页面,才会走指定的过滤器
十四 过滤器应用一:权限验证过滤器
需求:登录成功后,重定向到成功页面。未登录直接访问台页面则进行拦截,并跳转到登录页面
<form action="${pageContext.request.contextPath}/userServlet" method="post">
<table border="1" width="500">
<tr>
<td>用户名</td>
<td><input type="text" name="username" value="${ cookie.remember.value }"/></td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" name="password"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="登录"/></td>
</tr>
</table>
</form>
public class UserModel {
public User login(User user) throws SQLException {
// 连接数据库:通过传入的用户名和密码去数据库中进行查询
QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());
User existUser = queryRunner.query("select * from user where username = ? and password = ?",
new BeanHandler<User>(User.class), user.getUsername(), user.getPassword());
return existUser;
}
}
public class UserServlet extends HttpServlet{
protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException,IOException{
try{
//接收数据
String userName = request.getParameter("userName");
String password = request.getParameter("password");
//封装数据
User user = new User();
user.setUserName(userName);
user.setPassword(password);
//处理数据
UserModel userModel = new UserModel();
User existUser = userModel.login(user);
//根据处理结果跳转
if(existUser == null){
request.setAttribute("msg", "用户名或密码错误!");
request.getRequestDispatcher("/login.jsp").forward(request, response);
}else{
}
}catch (Exception e) {
e.printStackTrace();
}
}
}
public class LoginFilter implements Filter{
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//判断用户是否登录
HttpServletRequest req = (HttpServletRequest) request;
User existUser = req.getSession().getAttribute("existUser");
if(existUser == null){
req.setAttribute("msg", "你还没有登录,没有权限!");
req.getRequestDispatcher("/login.jsp").forward(req, response);
}else{
chain.doFilter(req, response);
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
十五 过滤器应用二:通用字符集编码过滤器
网站向后台提交中文数据(GET/POST),需要调用request.getParameter();方法接收数据,此时无论是get还是post接收的数据都存在乱码。
所以需要增强request的getParameter()方法,增强的过程要写在过滤器中。
如何增强一个类中的方法?
继承:必须要能够控制这个类的构造。
装饰者:被增强的类和增强的类需要实现相同的接口,在增强的类中获得被增强的类的引用。
缺点:接口中的方法过多,重写很多其他的方法。
动态代理:类需要实现接口
过滤器代码:
public class GenericEncodingFilter implements Filter{
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//在过滤器中增强request对象,并将增强后的request对象传递给Servlet
HttpServletRequest req = (HttpServletRequest) request;
//增强req
MyHttpServletRequest myReq = new MyHttpServletRequest(req);
chain.doFilter(myReq, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
增强类代码:
public class MyHttpServletRequest extends HttpServletRequestWrapper{
private HttpServletRequest request;
public MyHttpServletRequest(HttpServletRequest request) {
super(request);
this.request = request;
}
//增强request.getParameter();方法
public String getParameter(String name){
//获得请求方式
String method = request.getMethod();
//根据psot/get请求方式进行相应的乱码处理
if("GET".equalsIgnoreCase(method)){
//get的请求方式
String value = super.getParameter(name);
try {
value = new String(value.getBytes("ISO-8859-1"),"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return value;
}else if("PSOT".equalsIgnoreCase(method)){
//post的请求方式
try {
request.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return super.getParameter(name);
}
}
GenericEncodingFilter.java
/**
* 解决get和post请求 全部乱码
*
*/
public class GenericEncodingFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 转型为与协议相关对象
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 对request包装增强
HttpServletRequest myrequest = new MyRequest(httpServletRequest);
chain.doFilter(myrequest, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
// 自定义request对象
class MyRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
private boolean hasEncode;
public MyRequest(HttpServletRequest request) {
super(request);// super必须写
this.request = request;
}
// 对需要增强方法 进行覆盖
@Override
public Map getParameterMap() {
// 先获得请求方式
String method = request.getMethod();
if (method.equalsIgnoreCase("post")) {
// post请求
try {
// 处理post乱码
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (method.equalsIgnoreCase("get")) {
// get请求
Map<String, String[]> parameterMap = request.getParameterMap();
if (!hasEncode) { // 确保get手动编码逻辑只运行一次
for (String parameterName : parameterMap.keySet()) {
String[] values = parameterMap.get(parameterName);
if (values != null) {
for (int i = 0; i < values.length; i++) {
try {
// 处理get乱码
values[i] = new String(values[i]
.getBytes("ISO-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
hasEncode = true;
}
return parameterMap;
}
return super.getParameterMap();
}
@Override
public String getParameter(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
if (values == null) {
return null;
}
return values[0]; // 取回参数的第一个值
}
@Override
public String[] getParameterValues(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
return values;
}
}
Filter & Listener的更多相关文章
- JavaWeb三大组件(Servlet,Filter,Listener 自己整理,初学者可以借鉴一下)
JavaWeb三大组件(Servlet,Filter,Listener 自己整理,初学者可以借鉴一下) Reference
- servelt filter listener 的生命周期
1. servlet 当第一次请求一个servlet资源时,servlet容器创建这个servlet实例,并调用他的 init(ServletConfig config)做一些初始化的工作,然后 ...
- Filter&Listener
Filter&Listener 内容待补充... ...
- SpringBoot学习笔记(6)----SpringBoot中使用Servlet,Filter,Listener的三种方式
在一般的运用开发中Controller已经大部分都能够实现了,但是也不排除需要自己实现Servlet,Filter,Listener的方式,SpringBoot提供了三种实现方式. 1. 使用Bean ...
- ServletContextInitializer添加 servlet filter listener
ServletContextInitializer添加 servlet filter listener https://www.cnblogs.com/pomer-huang/p/9639322.ht ...
- SpringBoot---注册Servlet,Filter,Listener
1.概述 1.1.当使用 内嵌的Servlet容器(Tomcat.Jetty等)时,将Servlet,Filter,Listener 注册到Servlet容器的方法: 1.1.1.直接注册Bean ...
- SpringBoot整合WEB开发--(九)整合Servlet,Filter,Listener
简介: 如果需要整合第三方框架时,可能还是不得不使用Servlet,Filter,Listener,Springboot中也有提供支持. @WebServlet("/my") pu ...
- servlet filter listener interceptor 知识点
这篇文章主要介绍 servlet filter listener interceptor 之 知识点.博文主要从 概念,生命周期,使命介绍其区别.详情如下: 概念 生命周期 使命 servlet ...
- springboot之filter/listener/servlet
简介 SpringBoot可以简化开发流程,但是在其中如何使用传统的J2EE servlet/listener/filter呢 @Bean配置 在Configuration类中加入filter和ser ...
- servlet/filter/listener/interceptor区别与联系
转自:http://www.cnblogs.com/doit8791/p/4209442.html servlet.filter.listener是配置到web.xml中(web.xml 的加载顺序是 ...
随机推荐
- Java如何替换所有指定(出现)的字符串?
在Java编程中,如何替换所有指定(出现)的字符串? 以下示例演示如何使用Matcher类的replaceAll()方法替换字符串中的所有出现的子字符串. package com.yiibai; im ...
- rqalpha探究 2 接入mod
程序的目的是尽可能用mod扩展功能,所以接下来需要接入mod模块
- Eclipse使用心得与技巧
一. 常用快捷键(熟练使用快捷键可以充分提高编程效率,吐血整理...) 1,Alt + ↑上方向键:向上移动选中的代码,你可以把一行或者一段代码直接上移几行 2,Alt + ↓下方向键:向下移动选中的 ...
- file_name[:-4]
file_name: chair_0001.off file_name[:-4] : chair_0001
- 使用Android拨打电话功能
1.要使用Android系统中的电话拨号功能,首先必须在AndroidManifest.xml功能清单中加入允许拨打电话的权限: <uses-permission android:name=&q ...
- 【Docker】文件拷贝
从容器复制到主机sudo docker cp containerID:container_path host_path docker cp 5c6ce895b979:/root/LearnPaddle ...
- 从Elasticsearch来看分布式系统架构设计
分布式系统类型多,涉及面非常广,不同类型的系统有不同的特点,批量计算和实时计算就差别非常大.这篇文章中,重点会讨论下分布式数据系统的设计,比如分布式存储系统,分布式搜索系统,分布式分析系统等. 我们先 ...
- java转换图片压缩生成webp格式
http://blog.csdn.net/xu_san_duo/article/details/79085718
- Devart.Data.Oracle.OracleException: ORA-01480: STR 绑定值的结尾 Null 字符缺失,entity framework
1. 问题描述 这个问题主要的原因是 使用Devart oracle更新的时候 有中文的话 那就会出这个,其实就是 我们sqlserver 你没有加 N'' 这种的去更新 2. 解决方案 在连接字符串 ...
- SQL Server2012远程访问设置
http://jingyan.baidu.com/article/a681b0de3bdb7b3b19434667.html?qq-pf-to=pcqq.group 1.打开SQL server201 ...