友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
  
  
JSP入门教程(DOC格式)-第9部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
    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 + 〃退出。〃);  
}    
这里可以直接使用 listener 的username 操作在线列表,不必再去担心 session 
中是否存在username。  
valueUnbound 的触发条件是以下三种情况:  
    1。  执行 session。invalidate()时。  
    2。  session 超时,自动销毁时。  
    3。  执行 session。setAttribute(〃onlineUserListener〃; 〃其他对象〃);或 
       session。removeAttribute(〃onlineUserListener〃);将 listener 从 
       session 中删除时。  
因此,只要不将 listener 从 session 中删除,就可以监听到 session 的销毁。  
例子在 08…02 目录下,可以与08…01 对比一下异同,两者的最终效果是相同的。  
                                        82 / 148  
…………………………………………………………Page 83……………………………………………………………
                                        
                   第 9 章 封装 taglib 组件  
注意  
这里讲介绍自定义标签库(taglib),将原本需要写在 jsp 中的 java 代码封装 
起来,成为可复用的组件。  
taglib 本意是为了弥补 jsp 的先天不足,但它的笨重与复杂也颇为经典,可惜 
有的地方又不得不用,如果对其没有耐心尽可跳过。  
如果你不满足以下任一条件,请继续阅读,否则请跳过此后的部分,进入下一章: 
第 10 章 综合电子留言板。  
    1。  了解 taglib 的使用和制作。  
   2。  根本不想消除 jsp 中的 java 代码,也不打算写一些可以复用的组件。  
9。1。 用 taglib 实现循环  
回到联系簿的例子第 5。2 节  “Read(读取)”,不觉得这个 list。jsp 中的 java 
代码太碍眼了吗?  
  
                  
                    {contact。username}  
                    {contact。sex}  
                    {contact。email}  
                    {contact。qq}  
                    {contact。descn}  
                    修改 |  
删除  
                  
  
                                     83 / 148  
…………………………………………………………Page 84……………………………………………………………
                                        
如果能像使用 jsp 动作(action)一样,使用的形式进行循环该多好 
啊?可惜 jsp 动作(action)的功能太少了,它没办法进行循环,我们只好自己 
实现 taglib。  
比较一下使用taglib 前后 jsp 中的样子。  
  
      
        {contact。username}  
        {contact。sex}  
        {contact。email}  
        {contact。qq}  
        {contact。descn}  
        修改 
 | 删除 
  
      
  
          
taglib 的写法和 jsp 动作(action)很相似,是由taglib 前缀,冒号,标签名 
三者的组合体。其中 taglib 前缀是用 jsp 指令(direction)定义的。  
  
这里的 jsp 指令 (direction)是专门用来定义标签库的,uri 指定 tld 定义文 
件的位置,prefix 指定对应的 taglib 前缀。通过这里的定义才能在下面使用 
taglib。  
看看 taglib 带给了我们什么?  
    1。  items=〃{list}〃表示将对 list 变量进行循环操作。  
   2。  var=〃contact〃表示循环得到的每个元素对应的变量名。  
       taglib 中循环 list,每获得一个数据就通过 
       pageContext。setAttribute(〃contact〃; contact);放到 pageContext 中, 
       接着处理标签中包含的内容,这样标签中间的内容就可以通过 
       {context。username}的形式获得每一行的数据。  
了解过如何使用我们的 taglib,现在可以看具体实现了,首先我们要编写一个 
ForTag。java。  
                                     84 / 148  
…………………………………………………………Page 85……………………………………………………………
                                      
1。  第一步,让 ForTag 继承 BodyTagSupport。  
   BodyTagSupport 专门用来制作带内容的 taglib,它为我们提供了几个好 
   用的方法来处理数据。  
2。  第二步,为 ForTag 设置两个自定义参数:var 和 items。  
   对应标签中的,我们需 
   要在 ForTag 中写两个与其名称对应的 setter 方法。  
   public void setVar(String var) {  
       this。var = var;  
   }  
   public void setItems(Collection items) {  
       this。iterator = items。iterator();  
   }   
   这两个方法会在标签使用的时候,自动获得参数的值,供以后使用。  
3。  第三步,让 ForTag 处理标签内容。  
   public int doStartTag() throws JspException {  
       this。index = 0;  
        if  (this。process()) {  
            return EVAL_BODY_INCLUDE;  
       } else  {  
           return EVAL_PAGE;  
       }  
   }  
     
   public int doAfterBody() {  
       if  (this。process()) {  
           return EVAL_BODY_AGAIN;  
       } else  {  
           return EVAL_PAGE;  
       }  
   }  
   为了实现循环,我们需要监听两个事件。  
   doStartTag()方法在标签开始时执行,要记住每次都要对类进行初始化, 
   避免上一次的遗留数据对操作造成影响。然后判断是否有数据需要处理, 
   如果有,则返回 EVAL_BODY_INCLUDE 开始处理标签里的内容,如果没有, 
   返回 EVAL_PAGE 跳过标签内容执行标签下面的内容。  
                                  85 / 148  
…………………………………………………………Page 86……………………………………………………………
                                         
       doAfterBody()方法在每次处理完标签内部内容后执行,判断循环是否已 
       经结束,如果可以继续循环,返回 EVAL_BODY_AGAIN 用循环得到新的数据 
       再次处理标签内部内容,如果循环结束就返回 EVAL_PAGE 结束标签。  
   4。  第四步,进行循环时的处理。  
       private boolean process() {  
           if  (this。iterator。hasNext()) {  
               String row = this。index % 2 != 0 ? 〃odd〃  : 〃even〃 ;  
               pageContext。setAttribute(var + 〃_index〃; this。index);  
               pageContext。setAttribute (var + 〃_row〃; row);  
               Object item = this。iterator。next();  
               pageContext。setAttribute(var; item);  
               this。index++;  
               return true;  
           } else  {  
               return false;  
           }  
       }    
       process()方法在 doStartTag()和 doAfterBody()中都会用到,它的用途 
       是判断循环是否结束,如果还可以继续循环就返回 true,否则返回 false。  
       如果还可以继续循环,则从 iterator 中循环获得下一个数据,根据var 
       的值放到pageContext 中,同时放到pageContext 里的还有 index 索引值 
       和 row 索引值的奇偶,odd 代表奇数行,even 代表偶数行。var=〃contact〃 
       的情况下,{contact}表示循环数据,{contact_index}表示索引值, 
       {context_row}表示奇偶性,这些都可以在标签内部的 jsp 中直接使用。  
经过如此一番周折,ForTag 可以从标签获得参数,并对数据进行循环处理了。 
最后一步还要为它编写 tld (taglib definition)标签库定义文件,提供给 jsp 
指令(direction)引用。  
  
  
  
   1。0  
   1。2  
   lingirl  
   http://family168。/lingirl  
     
      for  
                                     86 / 148  
…………………………………………………………Page 87……………………………………………………………
                                          
      anni。ForTag  
        
         var  
         true  
         true  
         java。lang。String  
        
        
         items  
         true  
         true  
         java。util。Collection  
        
     
   
前面一大堆复杂难懂的标签指定我们使用 taglib 规范的版本,进入 tag 部分才 
开始定义名字为 for 的标签,使用 tag…class 指定对应的类,再定义两个参数: 
var 和 items。required 说明参数不能省略必须手工设置。rtexprvalue 表示参 
数部分可以使用 el,否则就只能用字符串。type 对应的是类中使用的真实类型, 
taglib 会根据它做类型转换。  
全部的例子在 09…01 目录下,注意编译taglib 需要将 jsp…api。jar 加入 
classpath,参考WEB…INF/src/pile。bat。  
结果,为了替换 4,5 行 java 代码,我们需要编写一个 ForTag。java,一个对应 
tld 文件,在 jsp 中引用 tld,最后才能使用ForTag 对 list 进行循环。不得不 
说一句:“太麻烦啦。”  
9。2。 关于 jstl  
taglib 太笨重,也太复杂了。编写一个 taglib 花费的力气太大,又不容易修改 
或扩展。一般情况下,taglib 都是由别人写好,我们再直接调用。sun 就为标签 
库定义了一套标准,叫做 jstl (java standard taglib)java 标准标签库,可 
以去http://jakarta。apache。org/taglibs/index。html 下载 apache 实现的 
jstl。  
想在项目里使用 jstl,首先要把 jstl。jar 和 standard。jar 两个文件放到 
/WEB…INF/lib/目录下。  
                                                                      
                                      87 / 148  
…………………………………………………………Page 88……………………………………………………………
                                       
然后在 list。jsp 中加入 jsp 指令(direction)引用 jstl 中定义的标签库。  
    
这里的 uri 是固定写法,只要写成这个就可以使用 jstl 了,jstl 中包含多个标 
签库,这里我们只用到 core。  
经过上述配置,现在可以使用 jstl 了,代码如下:  
  
    
      
        {contact。username}  
        {contact。sex}  
        {contact。email}  
        {contact。qq}  
        {contact。descn}  
        修改 
 | 删除 
  
      
  
这里使用的是 c:forEach,它也是一个执行循环的标签,var 和 items 参数的意 
义与上边谈到的 lingirl:for 标签已知,分别代表循环变量和循环数据。唯一不 
同的是多了一个varStatus 参数,这个参数表示当前行的状态,其中 
status。index 表示当前行的序号,我们就通过序号计算奇偶行。  
在 c:forEach 标签中,我们还看到一个 c:set 标签,它的作用是可以将指定的变 
量保存到作用域中,默认作用域是 page,这里我们使用 status。index 计算出行 
的奇偶性,然后保存到row 中,后面就可以直接使用{row}调用了。  
jstl 中的 c:forEach 不但可以处理 Collection,还可以处理数组和Map,使用 
jstl 我们更容易写出结构一致的代码,以初学 jsp 来说,自定义 taglib 还是太 
复杂了,所以还是先学习一些常用的 jstl 为好。  
例子在 lingo…sample/09…02 下,其中只有 list。jsp 中使用了 jstl。  
                                    88 / 148  
…………………………………………………………Page 89……………………………………………………………
                                               
                       第 10 章 综合电子留言板  
注意  
将前九章的知识结合起来,实现一个电子留言板,包括注册登录,发帖回复功能。  
如果你不满足以下任一条件,请继续阅读,否则请跳过此后的部分,进入下一章: 
第 11 章 文件上传。  
    1。  对电子留言板不感兴趣。  
10。1。 电子留言板用户指南  
首页显示的是主题列表。  
                                                                                                               
用户如果想发表新主题或者对主题进行回复,必须先注册为会员。  
                                                                                                               
                                           89 / 148  
…………………………………………………………Page 90……………………………………………………………
                                                                   
注册后进入登录页面进行登录。  
                                                                                                                                                               
登录后即出现在用户在线列表中。  
                                                                                                                                                               
点击标题可以看到主题的详细信息。  
                                                             90 / 148  
…………………………………………………………Page 91……………………………………………………………
                                                                    
                                                                                                                                                                 
登录以后即可发布新主题。  
                                                                                                                                                                 
10。2。 数据库设计  
数据库 er 图  
                                                              91 / 148  
…………………………………………………………Page 92……………………………………………………………
                                            
                                                                                                    
共定义了三张表:  
    1。  user 用户,保存注册用的信息。  
    2。  thread 主题,用户发起的主题帖子,外键关联 user,对应发表主题的用 
       户  
    3。  ment 回复,对主题帖子发起的回复,外键关联user 和 thread,对应 
       发表回复的用户和回复的主题。  
建表 sql 脚本放在 10…01/WEB…INF/sql/import。sql。  
…用户  
create table user 
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!