如何自定义标签

自定义标签的步骤:

1.创建一个自定义标签处理器类,实现SimpleTag接口

public class HelloSimpleMyTag implements SimpleTag {

2.在WEB-INF文件夹下新建一个.tld(标签库描述文件)为扩展名的xml文件.并拷入固定的部分:并对

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

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

<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>test</short-name>
  <!-- 作为tld文件的id,用来标示当前的tld文件,多个tld文件的uri不能重复,在
  JSP页面 通过 taglib 的属性 uri来引入tld文件     -->
  <uri>http://www.test.com/mytag/core</uri>
</taglib>

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

<tag>
      <!-- 标签的名字,在jsp页面上使用标签的名字 -->
      <name>hello</name>
      <!-- 标签所在的全类名 -->
      <tag-class>com.java.tag.HelloSimpleMyTag</tag-class>
      <!-- 标签体类型 -->
     <body-content>empty</body-content>
  </tag>

4.在jsp页面使用自定义标签

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

使用自定义标签时,prefix可以自己定义,通常会推荐tld文件中的<short-name>

-------------------------------------------------------------------------------------

通过使用自定义标签,会发现,标签处理器类的 setJspContext(),doTag()会被调用

public class HelloSimpleMyTag implements SimpleTag {

    @Override
    public void doTag() throws JspException, IOException {
    }

    @Override
    public JspTag getParent() {
        return null;
    }

    @Override
    public void setJspBody(JspFragment arg0) {
    }
  //JSP引擎调用
    @Override
    public void setJspContext(JspContext arg0) {
    }

    @Override
    public void setParent(JspTag arg0) {
    }

}    

在调用setJspContext(JspContext arg0) 时传入JspContext 对象,

通过J2EE API 发现

javax.servlet.jsp
Class JspContext

java.lang.Object
javax.servlet.jsp.JspContext
Direct Known Subclasses:
PageContext

PageContext 是 JspContext的一个子类,

在setJspContext(JspContext arg0) 是传入一个PageContext对象,

    private PageContext pageContext;
  //JSP引擎调用,把实际代表PageContext对象传入 @Override
public void setJspContext(JspContext arg0) { this.pageContext = (PageContext)arg0; }

其中PageContext为JSP的一个隐含对象,通过PageContext可以获取JSP页面的其他8个隐含对象

即可以在doTag()中对页面进行输出

   //执行标签体逻辑实际应该编写到该方法中 
  @Override
public void doTag() throws JspException, IOException { pageContext.getOut().print("HelloWorld!");
HttpServletRequest request = (HttpServletRequest)pageContext.getRequest();
pageContext.getOut().println("Hello: "+request.getParameter("name"));
    }

 

标签的属性:

<atguigu:hello value="aaa" count="10"/>

在标签上使用属性以下几个步骤

1.需要在tld文件中添加标签属性的描述

<tag>
      <!-- 标签的名字,在jsp页面上使用标签的名字 -->
      <name>hello</name>
      <!-- 标签所在的全类名 -->
      <tag-class>com.java.tag.HelloSimpleMyTag</tag-class>
      <!-- 标签体类型 -->
     <body-content>empty</body-content>
     <attribute>
         <!--该属性的名字,需要和标签处理器类settter 方法定义的属性相同  -->
         <name>value</name>
         <!-- 该属性是否必须 -->
         <required>true</required>
         <!--rtexprvalue :runtime expression value 
         当前属性是否可以接受运行时表达式的动态值  -->
         <rtexprvalue>true</rtexprvalue>
     </attribute>
     <attribute>
         <name>count</name>
         <required>false</required>
         <rtexprvalue>false</rtexprvalue>
     </attribute>
  </tag>
<!--rtexprvalue :runtime expression value 
         当前属性是否可以接受运行时表达式的动态值  -->
         <rtexprvalue>true</rtexprvalue>
可以动态赋值
<atguigu:hello value="${param.name }" count="10"/>

2.在标签处理器类中需要出现与上述属性名相同的成员变量

public class HelloSimpleMyTag implements SimpleTag {
    
//建议把所有类型都设置成String类型,因为从页面传过来是String类型
private String value; private String count; public void setValue(String value) { this.value = value; } public void setCount(String count) { this.count = count; }

当标签属性存在时会默认调用setXxx()

次需求为将value的值打印count次

<atguigu:hello value="${param.name }" count="10"/>
@Override
    public void doTag() throws JspException, IOException {
//        pageContext.getOut().println("HelloWorld!<br>");
//        HttpServletRequest request = (HttpServletRequest)pageContext.getRequest();
//        pageContext.getOut().println("Hello: "+request.getParameter("name"));
        JspWriter out  = pageContext.getOut();
        int c = Integer.parseInt(count);
        for(int i = 0;i<c;i++){
            out.print(value);
            out.print("<br>");
        }
    }

如何自定义标签_第1张图片

 

SimpleTag 有一个实现类 SimpleTagSupport

javax.servlet.jsp.tagext 
Interface SimpleTag

All Superinterfaces:
JspTag
All Known Implementing Classes:
SimpleTagSupport

通过继承SimpleTagSupport可以简化实现

public class HelloSimpleMyTag extends SimpleTagSupport {

有此获取PageContext

PageContext pageContext = (PageContext)getJspContext();

 

带标签体的自定义标签

1.若一个标签带有标签体

<test:bodyContent>HelloWorld</atguigu:test>

在自定义标签的标签处理器中使用JspFragment 对象封装标签体信息

2.若配置了标签含有标签体,则JSP引擎会调用SimpleTagSupport中的setJspBody(JspFragment jspBody)

把JspFragment对象传给标签处理器类,SimpleTagSupport中还定义了一个 protected JspFragment getJspBody()

用于返回JspFragment对象.

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

@Override
    public void doTag() throws JspException, IOException {
        super.doTag();
        JspFragment bodyContent = getJspBody();
        StringWriter sw = new StringWriter();
     //将标签体的内容输出到sw中
     bodyContent.invoke(sw); bodyContent.invoke(
null);

4.在tld文件中,使用body-content 节点来描述标签体的类型:

<body-content>:指定标签体的类型,大部分情况下,取值为scriptless.可能有3中取值:

empty:没有标签体

scriptless:标签体可以包含 el 表达式和 JSP 动作元素,但不能包含JSP的脚本元素

tagdependent:表示标签体交由标签本身去解析处理.

若指定tagdependent 在标签体中的所有代码都会原封不动的交给标签处理器,而不是将执行结果传递给标签处理器

如果指定 <body-content>scriptless</body-content>,在页面上使用

<atguigu:bodyContent><%=request.getParameter("name") %></atguigu:bodyContent>

会报错

使用<body-content>tagdependent</body-content>

<atguigu:bodyContent>${param.name }</atguigu:bodyContent>

页面上显示结果为 ${param.name }

 

example1: 写一个自定义标签将标签体内容变大写,重复time次 <test:printStr time="10">HelloWorld</test:printStr>

public class PrintTimesStr extends SimpleTagSupport{
    
    private String time;
    
    public void setTime(String time) {
        this.time = time;
    }
    
    @Override
    public void doTag() throws JspException, IOException {
        super.doTag();
        JspFragment bodyContent = getJspBody();
        StringWriter sw = new StringWriter();
        bodyContent.invoke(sw);
        String content = sw.toString().toUpperCase();
        int count = 1;
        try {
            count = Integer.parseInt(time);
        } catch (Exception e) {
        }
        for(int i = 0;i<count;i++){
            getJspContext().getOut().write(content+"<br>");
        }
    }

}
<tag>
      <name>printStr</name>
      <tag-class>com.java.tag.PrintTimesStr</tag-class>
      <body-content>scriptless</body-content>
      <attribute>
          <name>time</name>
          <required>true</required>
          <rtexprvalue>true</rtexprvalue>
      </attribute>
  </tag>
<test:printStr time="10">HelloWorld</test:printStr>

example2:模拟<c:forEach>

public class TestForEach extends SimpleTagSupport{
    
    private Collection<?> item;
    private String var;
    
    public void setItem(Collection<?> item) {
        this.item = item;
    }
    public void setVar(String var) {
        this.var = var;
    }
    
    @Override
    public void doTag() throws JspException, IOException {
        super.doTag();
        //遍历item对应的集合
        for(Object obj:item){
            //把正在遍历的集合放到pageContext中,键:var 值:正在遍历的对象
            getJspContext().setAttribute(var,obj);
            //把标签体内容直接输出到页面上
            getJspBody().invoke(null);
        }
    }

}
<tag>
      <name>forEach</name>
      <tag-class>com.java.tag.TestForEach</tag-class>
      <body-content>scriptless</body-content>
      <attribute>
          <name>item</name>
          <required>true</required>
          <rtexprvalue>true</rtexprvalue>
      </attribute>
      <attribute>
          <name>var</name>
          <required>true</required>
          <rtexprvalue>true</rtexprvalue>
      </attribute>
  </tag>
<%
        Customer customer1 = new Customer(1,"aa","[email protected]");
        Customer customer2 = new Customer(2,"bb","[email protected]");
        Customer customer3 = new Customer(3,"cc","[email protected]");
        List<Customer> customers = new ArrayList<Customer>();
        customers.add(customer1);
        customers.add(customer2);
        customers.add(customer3);
        request.setAttribute("customers", customers);
    %>

    <test:forEach var="customer" item="${requestScope.customers }">
        ${customer.id }--${customer.name }--${customer.email }<br>
    </test:forEach>

[email protected]
[email protected]
[email protected]

 

 

 

 

 

你可能感兴趣的:(如何自定义标签)