友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
第三电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

JSP入门教程(DOC格式)-第11部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!


                                          



    ControllerServlet  

    /user/*  

  

  

    ControllerServlet  

    /admin/*  

  

  

    ControllerServlet  

    *。do  

      



java 的复杂性在此处显露无疑。实际使用时,最好不要依赖web。xml 中的配置, 

在自己的类中实现灵活配置才是正途。  



7。3。2。 过滤链  



其实在 07…02 这个例子里,我们使用了两个过滤器,EncodingFilter 负责设置 

编码,SecurityFilter 负责控制权限,那这两个过滤器是怎么起作用的呢?它 

们两个同时过滤一个请求时谁先谁后呢?  



下面这个图会告诉我们答案。  



                                                                                         



所有的奥秘就在 Filter 中的FilterChain 中。服务器会按照web。xml 中过滤器 

定义的先后循序组装成一条链,然后一次执行其中的 doFilter()方法。执行的 

顺序就如上图所示,执行第一个过滤器的 chain。doFilter()之前的代码,第二 

个过滤器的 chain。doFilter()之前的代码,请求的资源,第二个过滤器的 



                                      75 / 148  


…………………………………………………………Page 76……………………………………………………………

                                     



chain。doFilter()之后的代码,第一个过滤器的 chain。doFilter()之后的代码, 

最后返回响应。  



因此在 07…02 中执行的代码顺序是:  



   1。  执行 EncodingFilter。doFilter()中 chain。doFilter()之前的部分: 

      request。setCharacterEncoding(〃gb2312〃);  

   2。  执行 SecurityFilter。doFilter()中 chain。doFilter()之前的部分:判断 

      用户是否已登录。  



      如果用户已登录,则访问请求的资源:/admin/index。jsp。  



      如果用户未登录,则页面重定向到:/failure。jsp。  



   3。  执行 SecurityFilter。doFilter()中 chain。doFilter()之后的部分:这里 

      没有代码。  

   4。  执行 EncodingFilter。doFilter()中 chain。doFilter()之后的部分:这里 

      也没有代码。  



过滤链的好处是,执行过程中任何时候都可以打断,只要不执行 

chain。doFilter()就不会再执行后面的过滤器和请求的内容。而在实际使用时, 

就要特别注意过滤链的执行顺序问题,像 EncodingFilter 就一定要放在所有 

Filter 之前,这样才能确保在使用请求中的数据前设置正确的编码。  



7。4。 filter 的详细配置  



我们已经了解了 filter 的基本用法,还有一些细节配置在特殊情况下起作用。  



在 servlet…2。3 中,Filter 会过滤一切请求,包括服务器内部使用 forward 转 

发请求和的情况。  



到了 servlet…2。4 中Filter 默认下只拦截外部提交的请求,forward 和 include 

这些内部转发都不会被过滤,但是有时候我们需要 forward 的时候也用到 

Filter,这样就需要如下配置。  



  

    TestFilter  

    anni。TestFilter  

  

  

    TestFilter  

    /*  

    REQUEST  

    FORWARD  



                                  76 / 148  


…………………………………………………………Page 77……………………………………………………………

                                          



    INCLUDE  

    EXCEPTION  

    



这样 TestFilter 就会过滤所有状态下的请求。如果我们没有进行设置,默认使 

用的就是 REQUEST。而EXCEPTION 是在 isErrorPage=〃true〃的情况下出现的,这 

个用处不多,看一下即可。  



这里 FORWARD 是解决request。getDispatcher(〃index。jsp〃)。forward(request;  

response);无法触发 Filter 的关键,配置上这个以后再进行 forward 的时候就 

可以触发过滤器了。  



Filter 还有一个有趣的用法,在 filter…mapping 中我们可以直接指定 

servlet…mapping,让过滤器只处理一个定义在web。xml 中的 servlet。  



  

    TestFilter  

    TestServlet  

  

  

  

    TestServlet  

    anni。TestServlet  

  

  

    TestServlet  

    /TestServlet  

    



直接指定 servlet…name,TestFilter 便会引用 TestServlet 配置的 

url…pattern,在某些 filter 与 servlet 绑定的情况下不失为一个好办法。  



                                      77 / 148  


…………………………………………………………Page 78……………………………………………………………

                                         



                第 8 章 配置 listener 监听器  



注意  



还记得我们之前讲过的在线列表吗?第 4。2 节  “例子:在线列表”。我们曾经 

说过那个在线列表无法判断用户非法退出,很可能造成在线列表无限增大,现在 

我们可以用 listener 来弥补这一问题了。  



如果你不满足以下任一条件,请继续阅读,否则请跳过此后的部分,进入下一章: 

第 9 章 封装 taglib 组件。  



    1。  了解如何使用HttpSessionListener 监听 session 的销毁。  

   2。  了解如何使用 HttpSessionBindingListener 监听 session 的销毁。  



8。1。 使用 HttpSessionListener  



编写一个 OnlineUserListener。  



package anni;  

  

import java。util。List;  

import javax。servlet。ServletContext;  

import javax。servlet。http。HttpSession;  

import javax。servlet。http。HttpSessionListener;  

import javax。servlet。http。HttpSessionEvent;  

  

public class OnlineUserListener implements HttpSessionListener {  

  

    public void sessionCreated(HttpSessionEvent event) {  

    }  

  

    public void sessionDestroyed(HttpSessionEvent event) {  

        HttpSession session = event。getSession();  

        ServletContext application = session。getServletContext();  

  

        // 取得登录的用户名  

        String username = (String) session。getAttribute(〃username〃);  

  

        // 从在线列表中删除用户名  

        List onlineUserList = (List)  

application。getAttribute(〃onlineUserList〃);  

        onlineUserList。remove(username);  



                                     78 / 148  


…………………………………………………………Page 79……………………………………………………………

                                        



  

        System。out。println(username + 〃超时退出。〃);  

    }  

  

}   



OnlineUserListener 实现了 HttpSessionListener 定义的两个方法: 

sessionCreated()和 sessionDestroyed()。这两个方法可以监听到当前应用中 

session 的创建和销毁情况。我们这里只用到 sessionDestroyed()在 session 

销毁时进行操作就可以。  



从 HttpSessionEvent 中获得即将销毁的 session,得到 session 中的用户名, 

并从在线列表中删除。最后一句向 console 打印一条信息,提示操作成功,这只 

是为了调试用,正常运行时删除即可。  



为了让监听器发挥作用,我们将它添加到 web。xml 中:  



  

  anni。OnlineUserListener  

   



以下两种情况下就会发生 sessionDestoryed (会话销毁)事件:  



    1。  执行 session。invalidate()方法时。  



       既然 LogoutServlet。java 中执行 session。invalidate()时,会触发 

       sessionDestory()从在线用户列表中清除当前用户,我们就不必在 

       LogoutServlet。java 中对在线列表进行操作了,所以 

       LogoutServlet。java 的内容现在是这样。  



       public void doGet(HttpServletRequest request;HttpServletResponse  

       response)  

           throws ServletException; IOException {  

           // 销毁 session  

           request。getSession()。invalidate();  

           // 成功  

           response。sendRedirect(〃index。jsp〃);  

       }   



   2。  如果用户长时间没有访问服务器,超过了会话最大超时时间,服务器就会 

       自动销毁超时的session。  



                                     79 / 148  


…………………………………………………………Page 80……………………………………………………………

                                       



      会话超时时间可以在 web。xml 中进行设置,为了容易看到超时效果,我们 

      将超时时间设置为最小值。  



         

          1  

          



       时间单位是一分钟,并且只能是整数,如果是零或负数,那么会话就永远 

       不会超时。  



对应例子在 08…01,为了验证 OnlineUserListener 是否能正常执行,我们可以 

登录两个用户,其中一个点击注销,另一个等待一分钟,然后可以在 console 

中看到输出的信息。  



                                                                  



8。2。 使用 HttpSessionBindingListener  



HttpSessionBindingListener 虽然叫做监听器,但使用方法与 

HttpSessionListener 完全不同。我们实际看一下它是如何使用的。  



我们的OnlineUserBindingListener 实现了HttpSessionBindingListener接口, 

接口中共定义了两个方法:valueBound()和 valueUnbound(),分别对应数据绑 

定,和取消绑定两个事件。  



所谓对 session 进行数据绑定,就是调用 session。setAttribute()把 

HttpSessionBindingListener 保存进 session 中。我们在LoginServlet。java 

中进行这一步。  



// 把用户名放入在线列表  



                                   80 / 148  


…………………………………………………………Page 81……………………………………………………………

                                         



session。setAttribute(〃onlineUserBindingListener〃; new  

OnlineUserBindingListener(username));  



这就是HttpSessionBindingListener和HttpSessionListener之间的最大区别: 

HttpSessionListener 只需要设置到 web。xml 中就可以监听整个应用中的所有 

session。HttpSessionBindingListener 必须实例化后放入某一个 session 中, 

才可以进行监听。  



从监听范围上比较,HttpSessionListener 设置一次就可以监听所有 session, 

HttpSessionBindingListener 通常都是一对一的。  



正是这种区别成就了 HttpSessionBindingListener 的优势,我们可以让每个 

listener 对应一个 username,这样就不需要每次再去 session 中读取username, 

进一步可以将所有操作在线列表的代码都移入 listener,更容易维护。  



valueBound()方法的代码如下:  



public void valueBound(HttpSessionBindingEvent event) {  

    HttpSession session = event。getSession();  

    ServletContext application = session。getServletContext();  

  

    // 把用户名放入在线列表  

    List onlineUserList = (List)  

application。getAttribute(〃onlineUserList〃);  

    // 第一次使用前,需要初始化  

    if  (onlineUserList == null) {  

        onlineUserList = new ArrayList();  

        application。setAttribute(〃onlineUserList〃; onlineUserList);  

    }  

    onlineUserList。add(this。username);  

}   



username 已经通过构造方法传递给 listener,在数据绑定时,可以直接把它放 

入用户列表。  



与之对应的 valueUnbound()方法,代码如下:  



public void valueUnbound(HttpSessionBindingEvent event) {  

    HttpSession session = event。getSession();  

    ServletContext application = session。getServletContext();  

  

    // 从在线列表中删除用户名  

    List onlineUserList = (List)  

application。getAttribute(〃onlineUserList〃);  



                                     81 / 148  


…………………………………………………………Page 82……………………………………………………………

                                            



    onlineUserList。remove(this。username);  

  

    System。out。println(this。username + 〃退出。〃);  

}    



这里可以直接使用 li
返回目录 上一页 下一页 回到顶部 0 0
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!