自定义标签

1 HelloWorld

创建一个标签处理器类:实现SimpleTag接口

在WEB-INF文件下面创建一个.tid(标签库描述文件)为扩展名的xml文件并考入固定部分

<taglib 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"
    version="2.0">
    <!-- 描述TLD文件 -->
    <description>MyTag 1.0 core library</description>
    <display-name>MyTag core</display-name>
    <tlib-version>1.0</tlib-version>
    
    <!-- 建议在JSP页面上使用的标签的前缀 -->
    <short-name>atguigu</short-name>
    <!-- 作为tld文件的ID ,用来唯一表示当前的TLD文件,多个tld 文件的URI 不能重复。通过JSP页面的taglib表签uri属性来应用-->
    <uri>http://www.atguigu.com/mytag/core</uri>
    
    
    <!-- 描述自定义的HelloSimpleTag标签 -->
    <tag>
    <!-- 标签名:JSP页面使用标签的名字 -->
        <name>hello</name>
        <!-- 标签所在的全类名 -->
        <tag-class>com.atguigu.javaweb.tag.HelloSimpleTag</tag-class>
        <!-- 标签体的类型 -->
        <body-content>empty</body-content>
    </tag>
</taglib>

并对description,display-name,tlib-version,short-name,uri做出修改

在tld文件中描述自定义标签

    <!-- 描述自定义的HelloSimpleTag标签 -->
    <tag>
    <!-- 标签名:JSP页面使用标签的名字 -->
        <name>hello</name>
        <!-- 标签所在的全类名 -->
        <tag-class>com.atguigu.javaweb.tag.HelloSimpleTag</tag-class>
        <!-- 标签体的类型 -->
        <body-content>empty</body-content>
    </tag>

在jsp页面使用自定义标签

》使用taglib指令导入标签库描述文件:

<%@taglib uri="http://www.atguigu.com/mytag/core" prefix="atguigu" %>

》使用标签:<atguigu:hello/>

 

setJSPContext:一定会被JSP引擎所调用,先于doTag,把代表JSP引擎的pageContext传给标签处理器类

    private PageContext pageContext;
    
    //JSP引擎调用,代表JSP页面PageContext对象传入
    //pageContext 可以获取JSP页面的其他八个隐含对象
    //所以凡是JSP页面可以做的标签处理器都可以完成
    @Override
    public void setJspContext(JspContext arg0) {
        System.out.println(arg0 instanceof PageContext);
        this.pageContext = (PageContext) arg0;
    }

带属性的自定义标签:

》现在标签处理器类中定义setter方法。建议把所有的属性都设置为String类型

    private String value;
    private String count;
    
    public void setValue(String value) {
        this.value = value;
    }
    
    public void setCount(String count) {
        this.count = count;
    }

 

在tld描述文件中描述属性:

        <!-- 描述当前标签的属性 -->
        <attribute>
            <!-- 属性名 ,需和标签处理器类的setter方法定义的属性相同-->
            <name>value</name>
            <!-- 该属性是否被必须 -->
            <required>true</required>
            <!-- rtexprvalue: runtime expression value 当前属性是否可以接受运行时表达式的动态值 -->
            <rtexprvalue>true</rtexprvalue>
        </attribute>

在页面中使用属性,属性名同tld文件中定义的属性名字

<atguigu:hello value="${param.name }" count="10"/>

 

通常情况下开发简单标签直接继承SimpleTagSupport就可以了,可以直接调用自己的getter方法得到的对应的API

 

public class SimpleTagSupport implements SimpleTag {

    private JspTag parentTag;

    private JspContext jspContext;

    private JspFragment jspBody;


    public SimpleTagSupport() {
        // NOOP by default
    }

    @Override
    public void doTag() throws JspException, IOException {
        // NOOP by default
    }

    @Override
    public void setParent( JspTag parent ) {
        this.parentTag = parent;
    }

    @Override
    public JspTag getParent() {
        return this.parentTag;
    }

    @Override
    public void setJspContext( JspContext pc ) {
        this.jspContext = pc;
    }

    protected JspContext getJspContext() {
        return this.jspContext;
    }

    @Override
    public void setJspBody( JspFragment jspBody ) {
        this.jspBody = jspBody;
    }

    protected JspFragment getJspBody() {
        return this.jspBody;
    }
}

 

正则表达式

 

package com.atguigu.javaweb.tag;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Pattern;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class ReadFuleTag extends SimpleTagSupport{
    
    //相对与当前WEB应用的根路径的文件名
    private String src;
    
    public void setSrc(String src) {
        this.src = src;
    }
    
    @Override
    public void doTag() throws JspException, IOException {
        PageContext pageContext = (PageContext) getJspContext();
        InputStream in = pageContext.getServletContext().getResourceAsStream(src);
        
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        
        String str = null;
        
        while((str = reader.readLine()) != null) {
            Pattern.compile("<").matcher(str).replaceAll("&lt");
            Pattern.compile(">").matcher(str).replaceAll("&gt");
            pageContext.getOut().write(str);
            pageContext.getOut().write("<br>");
        }
    }
}


    <tag>
        <name>readerFile</name>
        <tag-class>com.atguigu.javaweb.tag.ReadFuleTag</tag-class>
        <body-content>empty</body-content>
         <attribute>
            <name>src</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>       
    </tag>

<atguigu:readerFile src="/WEB-INF/note.txt"/>    

 

 

1.带标签体的自定义标签

1》若一个标签有标签体:
<atguigu:testJspFragment>HelloWorld</atguigu:testJspFragment>

在自定义标签处理器中使用JspFragment对象封装标签体信息
2》若配置标签韩有标签体,则JSP引擎会调用setJspBody()方法 把 JspFragment 传递给标签处理器类

在SimpleTagSupport 中还定义了一个getJspBody() 方法,用于返回JspFragment 对象

3》JspFragment 的invoke(Writer)方法:把标签体内容重Writer中输出,若为null,则等同于invoke(getJspContext().getOut()),及直接把标签体内容输出到页面上

有时可以借助StringWriter,先得到标签体的内容

//1.使用StringWriter得到标签体的内容
StringWriter sw = new StringWriter();
bodyContent.invoke(sw);
//2.把标签体的内容都变成大写
String content = sw.toString().toUpperCase();
//3.获取页面上隐含的out隐含对象输出到页面上
//System.out.println(sw.toString());
getJspContext().getOut().print(content);

4》在tld文件中,使用body-content节点来描述标签体的类型:
<body-content>:指定标签体的类型。可能取值的三种 大部分情况下取值scriptless
empty:没有标签体
scriptless:标签体可以包含el表达式和JSP动作元素,但不可以包含JSP的脚本元素
tagdependent:标签体交由本身解析处理。指定tagdependent,在标签体中的所有代码都会原封不动的交由标签体处理,而不是执行结果较有标签体处理

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

5>定义一个自定义标签:
<atguigu:printUpper time="10">asdf</atguigu>
把标签体内容转化为大写并输出time次到浏览器

6>实现foreach标签:
》两个属性:items(集合类型,Colllection),var(String 类型)
》doTag:
*遍历items对应的集合,
*把正在遍历的对象放入pageContext中,键:var,值;正在遍历的对象
*把标签体的内容直接输出到页面上

<c:forEach items="${requestScope.customers }" var="cust">
${pageScope.cust.id }--${cust.name }--<br>
</c:forEach>


2.开发有父标签的标签:

父标签无法获取子标签的引用,父标签仅把子标签作为标签体来使用

子标签可以通过getParent()方法来获取父标签的引用(需继承 SimplieTagSupport 或自实现SimplieTag接口的该方法)

若子标签的确有父标签,JSP引擎会把代表父标签的引用通过 setParent(JspTag parent)赋给标签处理器 。该标签是一个空接口 但是来统一SimpleTag 和 Tag的。实际使用需要类型的强制转换

在tld配置文件中,无需为父标签用额外的配置。但子标签是以标签体的形式存在的,所以父标签的<body-content></body-content>需要设置为scriptless

注意:父标签的类型是JspTag类型

实现:

<c:choose>
<c:when test="${param.age > 24}">大学毕业</c:when>
<c:when test="${param.age > 20}">高中毕业</c:when>
<c:otherwise>高中以下。。。</c:otherwise>
</c:choose>

开发标签3个:choose,when,otherwise
其中when标签有一个boolean类型的属性:test
choose是when 和 otherwise的标签的父标签, when 在otherwise 之前使用

在父标签choose中定义一个“全局” 的boolean类型的flag:用于判断子标签在满足条件下是否执行

*若when的test为true,且when的父标签的flag也为true,则执行when的标签体(正常输出标签体的内容),
同时把flag设置为false
*若when的test为true,且when的父标签的flag也为false,则不执行标签体
*若flag为true,otherwise执行标签体

posted @ 2020-03-20 23:10  野香蕉  阅读(108)  评论(0)    收藏  举报