在Java Web中,有三大组件,分别是Servlet,Filter.、Filter。对于,Servlet这个内容,在这一篇文章中,进行了很详细的讲解,http://blog.csdn.net/cs_hnu_scw/article/details/74080739 所以,本篇文章主要是讲解关于监听器和过滤器中的内容。
一:Listener监听器
知识点1:什么是监听器?
做过Swing或者AWT图像界面Java程序开发的话,应该对Listener与Event非常熟悉。Swing或者AWT中通过Listener与Event来处理事件,如鼠标事件、键盘事件等。先实现一个Listener接口,然后通过addListener()方法把Listener绑定到某个控件上,单机按钮时就会调用Listener的相应方法,并传回一个Event对象。
Java Web程序也一样,使用Listener与Event完成相应事件的处理。使用Listener不需要关注该类事件是怎样触发的或者怎么调用相应的Listener,只要记住该类事件触发时一定会调用相应的Listener。遵循Servlet规范的服务器完成了相应的工作。开发者只要在Listener里编写相关代码就OK了。
知识点2:八大监听器分别是哪些?
* Servlet的三大域对象:
* Request对象 – 一次请求
* Session对象 – 一次会话
* ServletContext对象 – Tomcat从启动到关闭
* JSP的四大域对象:
* page对象 – 当前页面
* Request对象
* Session对象
* ServletContext对象
* 第一组:用于监听Servlet三个域对象的创建与销毁
* ServletRequestListner
* HttpSessionListener
* ServletContextListener
* 第二组:用于监听Servlet三个域对象的属性变化(设置、删除、修改)
* ServletRequestAttributeListener
* HttpSessionAttributeListener
* ServletContextAttributeListener
* 第三组:用于通知被绑定到Session对象的属性.
* HttpSessionBindingListener
* 第四组:用于监听Session的钝化与活化
* HttpSessionActivationListener
它们各自的作用及其适用范围:
* 第一组:
* 作用:用于监听Servlet三个域对象的创建与销毁.
* 三个域对象的创建与销毁:
* Request对象:
* 创建:发生请求时.
* 销毁:请求完成时.
* Session对象:
* 创建:发生请求时,并且执行getSession()语句.
* 销毁:执行Session的销毁方法invalidate().
* ServletContext对象:
* 创建:Tomcat启动时.
* 销毁:Tomcat关闭时.
*第二组:
*作用:用于监听Servlet三个域对象的修改,删除,保存
如何自定义监听器:(针对第一组和第二组,因为它们两者非常类似)
* 第一步:
* 创建Java类,实现上述监听器接口之一.
* 重写该接口提供的所有方法.
* 第二步:
* 在web.xml文件中配置Listener.
<listener>
<listener-class>自定义Listener的完整路径</listener-class>
</listener>
* 第三组:HttpSessionBindingListener
* 注意:
* 该监听器应该由JavaBean类实现.(可以将JavaBean绑定到Session上)
* 谁被绑定到Session上,谁就实现该监听器.
* 该监听器的作用:通知被绑定到Session的JavaBean对象.
* 使用该监听器时,不需要在web.xml文件中进行配置的.
* 第四组:HttpSessionActivationListener
* Session的序列化
* 当Tomcat服务器正常关闭后,Session会自动被保存到本地硬盘中.
* 在Tomcat服务器的安装目录:%Catalina_HOME%\work\Catalina\localhost\Web工程名目录中.
* 当Tomcat服务器正常启动后,Session会自动从本地硬盘中读取到内存中.
* 保存在本地硬盘中的序列化文件,自动销毁.
* 问题:
* Tomcat服务器为什么提供这么一个机制?
* Session的钝化与活化
* 实现步骤:
* 编写Servlet设置Session.
* 在Tomcat安装目录%Catalina_HOME%\conf\Catalina\localhost目录中,创建一个名为Web工程名的xml文件.
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- maxIdleSwap:指定多长时间后Session会被钝化.(单位为分钟) -->
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1" >
<!--
directory:指定钝化文件的保存目录.
钝化文件保存路径:${CATALINA_HOME}\work\Catalina\localhost\Web工程名\${sessionid}.session
-->
<Store className="org.apache.catalina.session.FileStore" directory="mysession" />
</Manager>
</Context>
* 创建JavaBean,用于绑定到Session中.
* 该JavaBean实现了HttpSessionActivationListener接口,并且重写该接口提供的所有方法.
* 该JavaBean实现了Serializable(序列化)接口(Session的钝化与活化是基于Session的序列化实现的)
* Session钝化与活化和序列化的区别:
* Session序列化:
* Tomcat提供的自动机制.
* Session的序列化文件在重新被使用时,消失.
* Session钝化与活化:
* 手动实现.
* Session的钝化文件并不消失.
知识点3:实际案例之适用监听器———-完成在线人数的统计
第一步:编写web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>OnlineUserNumberComputer</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<listener>
<listener-class>com.hnu.scw.listener.MyContextServletListener</listener-class>
</listener>
<listener>
<listener-class>com.hnu.scw.listener.MySessionListener</listener-class>
</listener>
<servlet>
<description></description>
<display-name>OnLineUserNumberDemo</display-name>
<servlet-name>OnLineUserNumberDemo</servlet-name>
<servlet-class>com.hnu.scw.demo.OnLineUserNumberDemo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>OnLineUserNumberDemo</servlet-name>
<url-pattern>/OnLineUserNumberDemo</url-pattern>
</servlet-mapping>
</web-app>
第二步:编写监听器(这里用了servletContextListener和SessionListener两个监听器来完成)
监听器一:
package com.hnu.scw.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* 用于监听当servlet容器进行初始化的时候,将在线人数置为0
* @author scw
* 2018-2-3
*/
public class MyContextServletListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
//1:拿到contextservlet对象
ServletContext servletContext = servletContextEvent.getServletContext();
//2:初始化在线人数
servletContext.setAttribute("online", 0);
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
}
}
监听器二:
package com.hnu.scw.listener;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* 用于当用户登陆之后,在保存用户信息进入session的时候,将人数+1
* 当用户退出之后,将人数-1
* @author scw
*
*/
public class MySessionListener implements HttpSessionListener {
/**
* 当用户登陆之后,将用户信息保存进入session,那么就相当于在线人数+1
*/
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
ServletContext servletContext = httpSessionEvent.getSession().getServletContext();
int number = (int) servletContext.getAttribute("online");
number = number + 1 ;
servletContext.setAttribute("online", number);
}
/**
* 当用户退出的时候,即session会被销毁,所以在线人数要-1
*/
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
ServletContext servletContext = httpSessionEvent.getSession().getServletContext();
int number = (int) servletContext.getAttribute("online");
number = number - 1 ;
servletContext.setAttribute("online", number);
}
}
第三步:编写模拟用户成功登陆之后的Demo
package com.hnu.scw.demo;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* 用于模拟用户登陆之后进行的操作(这里只是模拟,实际开发当然不只下面这样处理了)
* scw
* 2018-2-3
*/
public class OnLineUserNumberDemo extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1:当进入的时候,就保存一个当前登陆用户的信息进入session(这是模拟登陆成功之后)
HttpSession session = request.getSession();
session.setAttribute("user", "我是用户");
//2:取出当前的登陆人数(因为之前保存在servletcontext中,所以从这里面取)
ServletContext servletContext = getServletContext();
int number = (int) servletContext.getAttribute("online");
//3:将当前的人数显示出在页面
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("当前在线人数为:" + number);
}
}
二:Filter过滤器
知识点1:什么是过滤器?
Filter译为过滤,是JavaEE的三大组件之一,用于在Servlet之外对Request或者Response进行修改。例如,污水净化设备可以看做现实中的过滤器,它负责将污水中的杂质过滤,从而使进入的污水变成净水。而对于Web应用程序来说,过滤器是一个驻留在服务器端的Web组件,它可以截取客户端和服务器端之间的请求与响应信息。
知识点2:过滤器使用的时机?
Filter的作用:起到过滤的作用.
Filter执行的时机:
(1)在执行对应的Servlet之前.(过滤Request对象中的内容)
(2)在执行对应的Servlet之后.(过滤Respons对象中的内容)
过滤器的发展:
* Filter最早在Servlet 2.3版本提供.
* Filter在Servlet 2.5版本完善.
知识点3:如何使用过滤器
Filter是JavaEE提供的一个接口.(自定义Filter需要实现该接口,并重写所有方法)
* Filter提供的方法:
* init()
* doFilter()
* destroy()
使用步骤:
(1)创建Java类,实现Filter接口,并且重写所有方法.
(2) 在web.xml文件中进行配置.
<filter>
<filter-name>实现接口的类名</filter-name>
<filter-class>实现接口的路径</filter-class>
</filter>
<filter-mapping>
<filter-name>类名</filter-name>
<url-pattern>/*</url-pattern> //需要进行过滤的url
</filter-mapping>
知识点4:过滤器的生命周期
* 出生:
* init()方法
* 活着:
* doFilter()方法
* 死去:
* destroy()方法
* 扩展知识:
* 面向对象:这个人就是对象,年龄、性别等是属性,出生、上学、结婚等方法.
* 类与对象的区别:
* 类:比作女生.
* 对象:就是范冰冰.
* 实现、继承、多态、封装等概念.
* 面向过程:这个人从出生,长大、上学、工作、…、去世.
知识点5:过滤器链
* 问题:
* 如何定义过滤器被执行的先后顺序?
* Filter的doFilter()方法具有一个参数FilterChain,通过调用chain.doFilter()方法可以放行.
* 在过滤器链中,执行chain.doFilter()方法,是否还是放行的作用?
* 如果是,应该被放行到哪里去了?(单个Filter时,直接被放行到对应的Web资源[Servlet、JSP])
* 解决以上问题:
* chain.doFilter()方法依旧是放行方法.
* 如果执行的不是过滤器链中最后一个过滤器的话,执行chain.doFilter()方法,会被放行到下一个过滤器里.
* 如果执行的是过滤器链中最后一个过滤器的话,chain.doFilter()方法,才会被放行到对应Web资源中.
* 过滤器链中的过滤器执行的先后顺序由web.xml文件中的<filter-mapping>标签定义的先后顺序决定.
* 实际开发的意义:
* 单个Filter完成单个任务.
知识点6:过滤器中init()方法中FilterConfig对象—–功能就类似servletConfig对象
* 读取web.xml文件中的初始化参数.
* 在web.xml文件中是如何配置的:
<filter>
<filter-name>实现接口的类名</filter-name>
<filter-class>实现接口的路径</filter-class>
<init-param>
<param-name>自定义需要初始化的参数名字key</param-name>
<param-value>自定义需要初始化的参数名字value</param-value>
</init-param>
</filter>
* FilterConfig的用法与ServletConfig一致.
* 在web.xml文件中配置全局初始化参数<context-param>,通过ServletContext对象读取.
知识点7:过滤器中的web.xml文件中的映射配置
* 完全匹配:/xxxx
* 目录匹配:/aaaa/
* 扩展名匹配:*.do
* 优先级别:完全匹配 -> 目录匹配 -> 扩展名匹配
* 如果当前Filter拦截对应Servlet的话:
* 还可以使用<servlet-name>标签
* Filter拦截Servlet默认情况是拦截直接请求.也就是说默认对于请求转发的是不会进行过滤拦截的(通过下面就可以进行拦截)
* 在web.xml文件中配置<filter-mapping>标签中具有<dispatcher>
* <dispatcher>标签在同一个Filter的配置中,可以配置多个.
* <dispatcher>标签的值:
* REQUEST:是默认值,表示一次请求.
* FORWARD:表示请求转发到.
* INCLUDE:表示包含(例如JSP包含另一个JSP等)
* ERROR:表示JSP的<%@ page errorPage=""%>
知识点8:实际案例之过滤器———–完成servlet中的全文乱码处理
描述:当进行servlet开发的时候,接受前台传送过来的中文,很多情况都碰到乱码,那么处理乱码就是一个问题,虽然有处理的方式,但是都是只针对一个servlet进行,那么一个项目中,肯定有很多个,那么如何进行处理呢?这时候就可以通过过滤器来进行实现,并且,这个开发好了,以后可以直接使用,或者直接打个Jar包,既方便又实用。
扩展:Servlet处理Get和Post的乱码问题
针对Get:
String value = request.getParameter("");
value = new String(value.getBytes("ISO8859-1"),"utf-8");
response.setContentType("text/html;charset=utf-8");
针对Post:——-post方式的较容易处理
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
开发步骤:
第一步:编写自定义的request对象
原因:因为对于Get方式的提交,那么处理中文会比较麻烦,就是因为要把所有的参数,都逐一进行编码处理,而常规的httprequest对象,则无法满足条件,所以需要自定义request对象。
package com.hnu.scw.filter.demo1;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* 自定义的Request对象
* @author scw
*/
public class MyRequest extends HttpServletRequestWrapper {
public MyRequest(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if(super.getMethod().equalsIgnoreCase("GET")){
try {
value = new String(value.getBytes("ISO-8859-1"),"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return value;
}
}
第二步:编写过滤器
package com.hnu.scw.filter.demo1;
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;
import javax.servlet.http.HttpServletResponse;
/**
* 当前Filter用于解决全站中文乱码问题.
* @author scw
*/
public class EncodingFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
//1 进行Request与Response对象的类型强转
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
//2 解决中文乱码问题:1)请求的中文乱码(GET\POST);2)响应的中文乱码.
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//3 创建自定义的Request对象
MyRequest myRequest = new MyRequest(request);
//3 放行
chain.doFilter(myRequest, response);
}
public void init(FilterConfig arg0) throws ServletException {
}
}
第三步:配置web.xml文件(就贴关键的过滤器配置,servlet的就不贴了)
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.hnu.scw.filter.demo1.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
第四步:进行测试
package com.hnu.scw.filter.demo1;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class EncodeServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");//接受传送过来的中文参数
System.out.println(username);//打印传送过来的get中文参数是否还乱码
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username"); //模拟post传送的参数
System.out.println(username); //打印接受过来的中文参数是否乱码
}
}
知识点9:实例之过滤器的使用————-自动登陆的功能
描述:有时候,我们会碰到,有些项目需要自动登陆功能,即当用户是之前登陆的,并且,用户选择了保存自动登陆,那么当下次再访问的时候,就不需要填写用户名和密码,而是直接能够正常访问,这个功能有时候还是很有用的。其实,这个通过过滤器就能够进行实现。
主要就写一下关于过滤器如何进行编写了,逻辑还是很清晰的。
过滤器类代码:
package com.hnu.scw.java.filter.demo2;
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;
/**
* 当前Filter用于完成用户自动登录功能.
* @author scw
*/
public class AutoLoginFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
Cookie[] cookies = request.getCookies();
if(cookies != null){
for (Cookie cookie : cookies) {
if(cookie != null){
String name = cookie.getName();
if("user".equals(name)){
// 曾经登录过
String value = cookie.getValue(); //下面进行分割,主要是因为cookie保存只能是字符串,那么用户的用户名和密码保存中间用了#字符来分割,所以这里就需要进行拆分
String username = value.split("#")[0];
String password = value.split("#")[1];
//将用户信息继续保存到session中,方便后面业务需要
request.getSession().setAttribute("user", username);
chain.doFilter(request, resp);
}else{
// 没有登陆过,就放行到登陆页面去处理即可。(模拟)
chain.doFilter(request, resp);
}
}
}
}else{
// 没有登陆过,就放行到登陆页面去处理(模拟)
chain.doFilter(request, resp);
}
}
public void init(FilterConfig arg0) throws ServletException {
}
}
注意:当进行登陆成功之后,再进行判断用户时候选择了自动登陆功能,然后将该用户的信息保存到cookie中,这样以后进行访问页面的时候,就从cookie中进行获取,判断是否有符合要求的cookie内容即可。这就是关键的登陆成功之后的操作。
好了,这就是对于J2EE中的两个关键组件的详细分析,是不是挺简单的呢?但是作用却是非常强大的,因为SpringMvc框架中,很多用的都是这部分的知识点,这对于以后学习框架有很大的帮助,所以,还是对于基础要好好的掌握。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/12413.html