原创讲解JSP过滤器和监听器
BeanSoft(刘长炯) 2007年11月
关于这个问题, 比较复杂的说. 不过我希望通过例子来解释会方便理解一些.
假设有一个非常危险的任务, 是九死一生. 需要你揣着炸药包从北平开车走高速路过保定去石家庄把鬼子的碉堡给炸了. 注意: 这个任务十分艰巨, 有可能半路炸药爆炸. 所以出发前你需要苦练10元一本的<<铁布衫>>, 还需要立遗嘱交代一下后事. 下面是路线图:
去时路线: 北平 ==> 高速路收费站入口(都有警察和警犬) A ==> 保定收费站 B ==> 石家庄收费站 C ==> 炸碉堡 D ==> 转车(刚才的车已经炸没了) E =>
回来路线: 石家庄收费站 ==> 保定收费站 ==> 高速路收费站出口(都有警察和警犬) A ==> 安全回到北平 G
那么我们先简介可能发生的情况. A 点有可能被警察和警犬发现, 所以你只能被扭送回北平. 即使不被发现, 还可能出现收费时发现10个现大洋一个路口的买路钱没带!! 哎, 只能又回去了. 还有最惨的: 高速路入口写着: 对不起, 到石家庄的路线因为施工不通! 只好回家等着吧.
到了B和C你可能还会被人发现带了炸药包, 或者发现买路费少带了! 极有可能又被扭送回北平, 注意已经在半道了, 是不会让你继续到石家庄的, 所以你会被从车上逮下来, 然后转到警车上带回来! 也就是从 B 或者 C 直接返回.
好了, 最佳情况就是你炸了碉堡, 也成功的返回了. 然后你可以开心的把<<铁布衫>>扔了, 然后宣告遗嘱作废.
OK, 以上过程, 就是过滤器和监听器的真实案例.
那么炸碉堡这个任务, 就相当于要调用 JSP 或者 Servlet 来获得执行结果(炸碉堡 D ). 在执行之前你需要做一些准备工作, 相当于要写一个
监听器 com.allanlxf.ums.web.ServiceListener
在里面你可以做一些事情例如初始化资源, 例如上文的苦练<<铁布衫>>, 立遗嘱, 这个相当于代码中的
public void contextInitialized(ServletContextEvent sce) 这样一个初始化事件.
那么在整个任务完成之后, 这些事情你就要考虑应该作废了, 所以需要
public void contextDestroyed(ServletContextEvent sce) 这样一个销毁事件, 例如把<<铁布衫>>扔了, 然后宣告遗嘱作废, 也就是收回资源.
那么过滤器在哪里呢? 它位于任务的 A B C 点. 注意是双向路程都会经过的. 也就是请求和响应都会经过. 但是过滤器也会检查不同的情况, 例如 A 点实际上有两个过滤功能: 查炸药包和收买路钱. 这就相当于配置了:
sessionFilter
* *.do
* REQUEST
* FORWARD
两个过滤功能都要检查. 如果成功了怎么办呢? 会继续让你走下一个路口, 注意不是让你直接成功. 也就是代码:
if(session.getAttribute("user") != null || path.equals("/login"))//若用户已经登录并且当前路径仍然停留在登录页面 {
chain.doFilter(request, response);//继续走下面的过滤器或者任务(不保证最终任务, 因为下个过滤器也可能让你回来)
只有当走到 C 点的时候, 下一步才是执行了最终的任务: 执行JSP或者Servlet.
}
反过来怎么办? 把你扭送上警车, 强行返回! 这样你连路口 B C 和最终任务都无法访问了. 也就是不会让你访问下一个过滤器和执行最终的 JSP 或者 Serlvet, 可以选择直接返回, 或者放警车上带回去.
{
return;// 直接返回
或者 response.sendRedirect(request.getContextPath() + "/login.jsp");//则扭送上警车, 强行返回到警察局
}
那么在 E 点发生了什么? 也就是你可能替换掉了原来的 response 对象, 也就是换车. 这意味着你可以在过滤器里私下修改请求和响应对象.
虽然已经不那么抽象了, 但是要理解可能还是需要耐心体会的.
=====================================================================
注: 原始问题
1.请看下面一段代码和其注释:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class SessionFilter extends HttpFilter
{
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException
{
String path = request.getServletPath();//取得该servlet的路径名称
path = path.substring(0, path.indexOf(".")); //获得路径中.之前的部分
HttpSession session = request.getSession();//从请求中取得session为得是从session中读取用户是否登录的标志值
if(session.getAttribute("user") != null || path.equals("/login"))//若用户已经登录并且当前路径仍然停留在登录页面
{
* chain.doFilter(request, response);//则将当前滤镜加入到滤镜链条当中
}else//若用户尚未成功登录
{
response.sendRedirect(request.getContextPath() + "/login.jsp");//则使用请求重定向转到登录页面
}
}
}
/*
* 该Filter滤镜类所过滤的是用户在浏览器中输入的
* 当前web application的访问路径,通过判断用户是
* 否成功登录而决定是否对访问路径加以限止
* 在该web application的web.xml配置文件中为
* 该filte滤镜做了相应配置
*/
请问: 上面代码FilterChain对象盛装的是Filter对象, 可它是怎么工作的啊?
加*号的语句是何用意啊,不是过滤路径吗, 为什么要将请求与响应加入呢?
2.请看下面一段代码:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public abstract class HttpFilter implements Filter
{
private FilterConfig config;
public void init(FilterConfig config) throws ServletException
{
this.config = config;
init();
}
public void init() throws ServletException
{
}
public String getInitParameter(String name)
{
return config.getInitParameter(name);
}
public ServletContext getServletContext()
{
return config.getServletContext();
}
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws ServletException, IOException
{
doFilter((HttpServletRequest)request, (HttpServletResponse)response, chain);
}
public abstract void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException;
public void destroy()
{
}
}
请问: 该类就这样写了一下,没有包含任何行为,它如何完成过滤工作啊?
3.请看下面代码:
package com.allanlxf.ums.web;
import javax.servlet.*;
//import javax.servlet.http.*;
import com.allanlxf.ums.service.SystemService;
import com.allanlxf.ums.service.StudentService;
public class ServiceListener implements ServletContextListener
{
public void contextInitialized(ServletContextEvent sce)
{
ServletContext application = sce.getServletContext();
StudentService service = new StudentService();
application.setAttribute("studentService", service);
SystemService systemService = new SystemService();
application.setAttribute("systemService", systemService);
}
public void contextDestroyed(ServletContextEvent sce)
{
}
}
/*
*本类是该web application的监听器类,在该类中,
*将两个无为本系统提供服务的两个对象写入到了
*application隐含对象中(这样保证在该系统的任何
*地方都能够取得这两个服务类对象的引用)
*在本系统的web.xml文件中对该监听器做了配置
*/
请问: 为什么要将服务类对象写入到程序上下文中呢,直接创建不也一样吗?
监听器只有这样的功能吗,是否还有其它功能呢?
3.请看下面的配置文件内容:
sessionFilter
com.allanlxf.ums.web.SessionFilter
sessionFilter
* *.do
* REQUEST
* FORWARD
com.allanlxf.ums.web.ServiceListener
请问: 加*号的三项是什么意思?
当初老师讲的时候,许多基本的原则原理尚不清楚,这些根本没有听明白,当然,老师也未细讲,只说会用即可, 可是若不能明白其本质,用也只能用这一点儿, 怎么成呢, 希望您能够比较详悉的讲一下. thank you very much!
文章来源:
http://www.blogjava.net/beansoft/archive/2007/11/09/159374.html