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 的加载顺序是 ...
随机推荐
- Windows 8(64位)如何搭建 Android 开发环境与真机测试(转)
可以参考http://wenku.baidu.com/link?url=ghU6IFS1WJXLFKfM_0efv9YQEnMDBrdi9CXwirSs5IOLLeUfdIOh8OOVv0DX89Lt ...
- linux环境中,多个命令之间,通过&& ||执行,命令之间执行的逻辑是什么?
需求描述: 最近在写一个脚本的时候,要判断一个文件是否存在,有怎么样,没有就创建,这个时候 看到了一个test 结合 || 或者 &&的写法,就查看了下资料记录下是怎么个玩法. 操作过 ...
- .net运行时dll的查找路径顺序
D:\项目路径\.target\项目名.BLL.pdb”.已完成生成项目“D:\项目路径\项目名.BLL\项目名.BLL.csproj”(默认目标)的操作.ResolveAssemblyReferen ...
- day_6.8 py 网络编程
2018-6-8 18:20:30 OSI模型:就是七层物理层 ICMP 我ping你的时候要用,不仅要知道ip地址和网卡号mac地址 ARP 在我和你通讯前不知道的mac地址需要广播一下,当我说的 ...
- vue 数据管道
文档https://cn.vuejs.org/v2/guide/filters.html html 片段 <div class="app"> <div>{{ ...
- asp.net C#绘制太极图
成品图: html页面: 注意设置 ContentType="Image/Jpeg" <%@ Page Language="C#" AutoEventWi ...
- base标签浏览器兼容问题
<% String path = request.getContextPath(); String basePath = request.getScheme() + "://" ...
- hdu4300 Clairewd’s message【next数组应用】
Clairewd’s message Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- 一劳永逸:域名支持通配符,ASP.NET Core中配置CORS
ASP.NET Core 内置了对 CORS 的支持,使用很简单,只需先在 Startup 的 ConfigureServices() 中添加 CORS 策略: public void Configu ...
- MS14-064 漏洞测试入侵——20145301
MS14-064 漏洞测试入侵 Microsoft Windows OLE远程代码执行漏洞,OLE(对象链接与嵌入)是一种允许应用程序共享数据和功能的技术 执行摘要 此安全更新可解决 Microsof ...