2009-12-13传智播客java web——传统标签与简单标签

         除了JavaMail今日是JavaWeb部分的最后一天了,还有三天的时间是做个小项目。将之前学习的所有知识串起来,准备迎接高级部分。嘿嘿!终于到了高级部分!

         今日主要内容是JSP自定义标签与JSTL,之前有使用过JSTL,十分的方便,还有EL。也有学过自定义EL函数,但个人感觉EL自定义函数没有JSP的自定义标签有趣。

一、JSP自定义标签

我们知道,JSP在被访问时会被JSP引擎翻译为Servlet程序,即JSP就是Servlet程序。我们可以在JSP中插入Java代码,但是在JSP页面中使用<%...%>嵌入JAVA代码,使用页面编写起来十分混乱,更不利于以后的维护。因为,JSP自定义标签可以优雅的解决这一问题。JSTL也正是SUN为些开发的一个标签库,接下来让我们来编写自己的自定义标签。

定义JSP自定义标签,需要四个步骤:

1.        编写一个实现Tag接口的Java类(标签处理器类),覆盖其中的doStartTag方法,在doStartTag方法中编写标签的功能代码。

2.        编写标签库描述符(tld)文件,在tld文件中对自定义标签进行描述。

3.        WEB应用中部署和安装自定义标签库。

4.        JSP页面中导入和使用自定义标签。

在以前的JSP页面编写中,我们有使用过“<cc:if test=”逻辑表达方式”>”和<cc:froEach var=”变量” items=”集合、列表、数组”>。下面我们就来实现与这两个JSP标签类似功能的自定义JSP标签。

1.编写<cc:if test=”…”>…</cc:forEach>自定义标签:

IfTag.java,标签处理器:

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.Tag;

 

public class IfTag implements Tag {

    private boolean test;

    public void setTest(boolean test) {

       this.test = test;

    }  

    public int doStartTag() throws JspException {

       if(this.test)

           return Tag.EVAL_BODY_INCLUDE;

       return Tag.SKIP_BODY;

    }

    public int doEndTag() throws JspException {

       // TODO Auto-generated method stub

       return 0;

    }

    public Tag getParent() {

       // TODO Auto-generated method stub

       return null;

    }

    public void release() {

       // TODO Auto-generated method stub

    }

    public void setPageContext(PageContext arg0) {

       // TODO Auto-generated method stub

    }

    public void setParent(Tag arg0) {

       // TODO Auto-generated method stub

    }

}

1.        private boolean test;”,这个成员名称必须与JSP中自定义标签的属性名称相同,JSP引擎会通过“setTest”方法,将属性值传递过来。

2.        doStartTag()”当自定义标签开始被执行时,JSP引擎会调此方法。在此方法中可以“Tag.EVAL_BODY_INCLUDE”告诉JSP引擎继续向下执行标签体中的内容,如果返回“Tag.SKIP_BODYJSP引擎将不执行标签体中的内容。

3.        doEndTag()”当标签体被执行完成后,会调用些方法。

4.        getParent()”返回父标签。

5.        release()”,当标签处理器被销毁前会调用此方法,可以在此方法中释放。但这个处理器被JSP引擎实例化后,一般不会被释放而是保存在内存中,留以后用。服务器被关闭时,会被释放。

6.        setPageContext(PageContext arg0)”,JSP引擎将JSP页面的运行环境,通过此方法传递给自定义标签处理器。

7.        setParent(Tag arg0)”,如果标签有父标签时,JSP引擎会将父标签对象传递进来。

 

MyEl.tld,自定义标签描述文件。

<?xml version="1.0" encoding="UTF-8"?>

<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"

 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">

    <tlib-version>1.0</tlib-version>

    <short-name>SimpleTagLibrary</short-name>

    <uri>/SimpleTagLibrary</uri>

   

    <tag>

       <name>myIf</name>

       <tag-class>cn.itcast.cc.jsptag.IfTag</tag-class>

       <body-content>JSP</body-content>

       <attribute>

           <name>test</name>

           <required>true</required>

           <rtexprvalue>true</rtexprvalue>

       </attribute>

    </tag>

</taglib>

1.        tld文件在工程中的存放位置,与web.xml存位置相同。

2.        <uri>”设置tld描述文件的URIURI用于在JSP页面中引入此tld文件。

3.        <tag>”定义一个自定义标签。

4.        <name>”自定义标签名。

5.        <tag-class>”自定义标签处理器类,就是上边编写的类。

6.        <body-content>”自定义标签的标签体内容。(也可以设置为“empty”等)

7.        <attribute>”为自定义标签添加一个属性。

8.        <name>”自定义标签属性名。

9.        <required>true为必须指定此属性,false此属性可为空。

10.     <rtexprvalue>”设置属性为静态的或是动态的。如果为false即静态的,静态的属性值JSP引擎会将它自动转换(必须是java8种基本数据类型),比如<cc:MyIf test=”122”>JSP引擎会自动将“123”转换为整数型,所以处理器的类成员可以定义为int型。如果为true即动态的,如果设置为将类型设置为Object可以接收任意数据类型的属性。

 

Index.jsp,在JSP页面中引入自定义标签,并调用自定义标签:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<%@taglib prefix="cc" uri="/SimpleTagLibrary" %>

<html>

  <head>

  </head>

 

  <body>

    <cc:myIf test="${2>1}">

       自定义逻辑判断标签!

    </cc:myIf>

  </body>

</html>

 

2.编写<cc:foEach var=”temp” items=”list”>…</cc:forEach>自定义标签:

forEahTag.java,继承自SimpleTagSupport,这个简单简化了Tag接口的操作。

import java.io.IOException;

import java.util.*;

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.tagext.SimpleTagSupport;

 

public class forEahTag extends SimpleTagSupport {

 

    // 记录 items="xxx" 中的list对象

    private List items;

    // 记录 var="xxx"中的变量名称

    private String var;

 

    public void setItems(List items) {

       this.items = items;

    }

 

    public void setVar(String var) {

       this.var = var;

    }

    // SimpleTagSupport简化了Tag接口的操作,在此只需要覆盖doTag方法即可实现forEach

    @Override

    public void doTag() throws JspException, IOException {

       Iterator iter = this.items.iterator();

       while (iter.hasNext()) {

           // 将单个对象设置到Context域中,在JSP页面中可以使用${var}获取对象。

           this.getJspContext()

                  .setAttribute(this.var, iter.next());

           // 调用执行标签体,需要一个输出流参数,

           // 设置为nullJSP引擎自动将其替换为this.getJspContext().getOut()

           this.getJspBody().invoke(null);

       }

    }

}

 

this.getJspBody()”返回JspFragment对象,JspFragment代表一个标签体。JspFragment中不能包含JSP脚本元素。JspFragment.invoke就是调用标签体。如果不调用此方法,就是忽略标签体。

forEach也可以使用实现TagSupport接口实现,当标签体被调用时,首先会调用“doStartTag”方法(只会调用一次),可以在这个方法里先输出第一个成员。然后执行标签体,最后调用“doAfterBody”方法,它是重点。在这个方法里再输出下一个成员然后判断是不是到了list尾,如果到了list结尾则返回IterationTag. SKIP_BODY;。如果没有到list结尾则返回IterationTag. EVAL_BODY_AGAIN;,继续重复执行标签体,实现对list的遍历!

MyEl.tld,添加如下内容:

    <tag>

       <name>myForEach</name>

       <tag-class>cn.itcast.cc.jsptag.forEahTag</tag-class>

       <body-content>scriptless</body-content>

       <attribute>

           <name>var</name>

           <required>true</required>

           <rtexprvalue>true</rtexprvalue>

       </attribute>

       <attribute>

           <name>items</name>

           <required>true</required>

           <rtexprvalue>true</rtexprvalue>

       </attribute>

    </tag>

         <body-content>scriptless</body-content>”指定标签体内为非脚本代码。

 

Index.jsp添加如下内容:

<%

       List list = new ArrayList();

       list.add("");

       list.add("");

       list.add("");

       this.getServletContext().setAttribute("list",list);

     %>

    <cc:myForEach items="${list}" var="temp">

       ${temp }

    </cc:myForEach>

         JSP页面插入的代码,是向List对象中插入成员,然后添加到ServletContext域中,${list}ServletContext域中获取list对象。

 

         3.JSP自定义标签高级部分:

修改标签内容的标签<cc:htmlFilter><cc:readFile>两个标签配合使用。

ReadFileTag.java

public class ReadFileTag extends SimpleTagSupport {

    // 记录文件路径

    private String src;

      

    public void setSrc(String src) {

       this.src = src;

    }

 

    @Override

    public void doTag() throws JspException, IOException {

       // 获取到文件的全路径

       PageContext pc = (PageContext) this.getJspContext();

       ServletContext sc = pc.getServletContext();

       String file = sc.getRealPath(src);

       // 使用字符缓冲流读取文件

       BufferedReader reader = new BufferedReader(new FileReader(file));

       String line = null;

       while((line = reader.readLine()) != null){

           // 写到输出流

           this.getJspContext().getOut().write(line + "\r\n");

       }     

    }

}

         注意代码中的写到输出流,这个输出流是父标签传递进来的输出流。

 

HtmlFilter.java

public class HtmlFilter extends SimpleTagSupport {

 

    @Override

    public void doTag() throws JspException, IOException {

       // 调用子标签,并将输出流传递进去。

       CharArrayWriter caw = new CharArrayWriter(); 

       this.getJspBody().invoke(caw);

       //这里之所以要写义一个输出流,是为了实现Html字符的转换

       this.getJspContext().getOut().write(filter(caw.toString()));

       System.out.println(caw.toString());

    }

   

    // Html字符转换

    public static String filter(String message) {

 

        if (message == null)

            return (null);

 

        char content[] = new char[message.length()];

        message.getChars(0, message.length(), content, 0);

        StringBuffer result = new StringBuffer(content.length + 50);

        for (int i = 0; i < content.length; i++) {

            switch (content[i]) {

            case '<':

                result.append("&lt;");

                break;

            case '>':

                result.append("&gt;");

                break;

            case '&':

                result.append("&amp;");

                break;

            case '"':

                result.append("&quot;");

                break;

            default:

                result.append(content[i]);

            }

        }

        return (result.toString());

    }

}

         调用标签体时,之所以传递一个自定义的输出流。是因为,使用这个输出流,获取读到的html文件的内容。然后将流中的html字符转换后,再输出到JSP页面。

         二、JSTL标签

         1.jstl标签分为:

         核心标签库

国际化标签

数据库标签

XML标签

JSTL函数

         因为在JSP页面中最好不要访问数据库和XML文件,这样太不安全了而且程序逻辑混乱,所以就没有讲解这方面的使用。

 

         2.jstl常用的标签:

         (1).<c:out>标签:用于输出一段文本内容到pageContext对象当前保存的“out”对象中。

         (2). <c:set>标签:用于设置各种Web域中的属性,或者设置Web域中的java.util.Map类型的属性对象或JavaBean类型的属性对象的属性。

         (3). <c:remove>标签:用于删除各种Web域中的属性。

         (4). <c:catch>标签:用于捕获嵌套在标签体中的内容抛出的异常。

         (5). <c:if test=“”>标签:可以构造简单的“if-then”结构的条件表达式。

         (6). <c:choose>标签:用于指定多个条件选择的组合边界,它必须与<c:when><c:otherwise>标签一起使用。

         (7). <c:forEach>标签:用于对一个集合对象中的元素进行循环迭代操作,或者按指定的次数重复迭代执行标签体中的内容。

         (8). <c:param>标签:它可以嵌套在<c:import><c:url><c:redirect>标签内,为这些标签所使用的URL地址附加参数。此标签自动进行URL编码。

         (9). <c:url>标签:用于在JSP页面中构造一个URL地址,其主要目的是实现URL重写。还记得URL重写是什么吗?当session被禁用时,URL重写就是为解决这一问题的!

         (10). <c:redirect>标签:用于将当前的访问请求转发或重定向到其他资源。

      

         OK,上面是常用的标签,使用方法去查手册吧!东西太多了。老方今天特别提到一个标签,是佟老师特别指出的。它在Structs中使用较多——C:check permission

 

         比如,一个管理页面,有好多管理选项。但管理选项需要根据用户的权限进行显示,此时自定义一个检查标签,将User做为参数传递给标签处理器。标签处理器查看User的权限,然后确定是否执行标签体。(标签体中的内容为显示相应的管理选项)

 

         OK,明天就要老方就开始编写一个将JavaSeb基础部分的所有内容融会到一起的WEB应用用例。估计使用1天多点的时间。然后同学们有近两天的个人实现时间。大家对此都十分期待!终于应用这段时间所学的知识,写个像样的东西出来。

 

         加油!

你可能感兴趣的:(2009-12-13传智播客java web——传统标签与简单标签)