码迷,mamicode.com
首页 > 其他好文 > 详细

自定义标签

时间:2016-11-06 22:13:12      阅读:318      评论:0      收藏:0      [点我收藏+]

标签:gui   param   source   list   writer   public   sch   utf-8   包含   

1 如果在jsp页面中写java代码 是很不合适的 而且坏处很多
像这样:

<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@page import="com.atguigu.javaweb.Customer"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
// 模拟Servlet的操作
List<Customer> customers=new ArrayList<Customer>();
customers.add(new Customer("bean1","fjnu","A","1"));
customers.add(new Customer("bean2","fjnu","B","2"));
customers.add(new Customer("bean3","fjnu","C","3"));
customers.add(new Customer("bean4","fjnu","D","4"));
customers.add(new Customer("bean5","fjnu","E","5"));
customers.add(new Customer("bean6","fjnu","F","6"));
request.setAttribute("customers", customers);
%>

<jsp:forward page="testtag.jsp"></jsp:forward>

</body>
</html>

<%@page import="com.atguigu.javaweb.Customer"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 在页面上对request中的customers属性进行遍历 打印属性 -->
<%
//不使用标签遍历的情况
List<Customer> customers= (List<Customer>)request.getAttribute("customers");

if(customers!=null)
{
for(Customer customer:customers)
{
%>
<%=customer.getName()%>,<%=customer.getAddress() %>,<%=customer.getCardType() %>,<%=customer.getCard() %>


<% }
}

%>
</body>
</html>

所以我们需要使用自定义标签

2 使用标签 需要导入JSTL标签库

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<!-- 在页面上对request中的customers属性进行遍历 打印属性 -->
<%-- 使 用标签库 --%>
<c:forEach items="${requestScope.customers}" var="customer">
-- ${customer.name}
</c:forEach>

这样就可以实现遍历了 代码简洁而且更加舒服

3 如何自定义标签
凭什么一个小小的标签 有如此巨大的功能 其背后还隐藏了什么?

其实背后还有一个类(标签处理器类)再对其支撑

开发自定义标签 其实就自定义标签处理器类

4 标签的形式
空标签
带有属性的空标签
带有内容的标签
带有内容和属性的标签

5 自定义标签的开发
1)编写完成标签功能的java类(标签处理器类) 实现SimpleTag接口
2)编写标签描述文件(tld)文件 在tld文件中对自定义标签进行描述(后缀为.tld的XML文件)
对description display-name tlib-version short-name uri进行响应修改
3)在jsp页面中导入和使用自定义标签

一个自定义标签的helloworld

tld 文件

<?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>

<!--建议使用的标签前缀 -->
<short-name>bean</short-name>
<!--作为tld文件的id,用来唯一标识当前的tld文件 多个tld的文件的uri不能重复 通过在JSP页面上的tiglib标签的uri属性进行引用-->
<uri>http://www.bean.com/mytag/core</uri>

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

标签处理器类

package com.bean.tag;

import java.io.IOException;

import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTag;

public class HelloSimpleTag implements SimpleTag {

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

System.out.println("doTag");
}

@Override
public JspTag getParent() {
System.out.println("getParent");
return null;
}

@Override
public void setJspBody(JspFragment arg0) {
System.out.println("setJspBody");

}

@Override
public void setJspContext(JspContext arg0) {
System.out.println("scj");

}

@Override
public void setParent(JspTag arg0) {
System.out.println("sp");

}

}


使用自定义标签
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>

<!-- 导入标签库(描述文件) -->
<%@taglib uri="http://www.bean.com/mytag/core" prefix="bean"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>

<bean:hello/>

</body>
</html>

setJspContext: 一定会被 JSP 引擎所调用, 先于 doTag, 把代表 JSP 引擎的 pageContext 传给标签处理器类.
从pageContext可以获取其它JSP页面上隐含的其它8个对象

6带属性的自定义标签

①. 先在标签处理器类中定义 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"/>

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

public class SimpleTagSupport implements SimpleTag{

public void doTag()
throws JspException, IOException{}

private JspTag parentTag;

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

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

private JspContext jspContext;

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

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

private JspFragment jspBody;

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

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

7带属性的标签练习实例

1)利用标签计算出两个值的最大值

package com.atguigu.javaweb.tag;

import java.io.IOException;

import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class MaxTag extends SimpleTagSupport{

private String num1;
private String num2;

public void setNum1(String num1) {
this.num1 = num1;
}

public void setNum2(String num2) {
this.num2 = num2;
}

@Override
public void doTag() throws JspException, IOException {
int a = 0;
int b = 0;

PageContext pageContext = (PageContext) getJspContext();

JspWriter out = pageContext.getOut();

try {
a = Integer.parseInt(num1);
b = Integer.parseInt(num2);
out.print(a > b ? a : b);
} catch (Exception e) {
out.print("输入的属性的格式不正确!");
}

}

}


2)读取文件
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 ReadFileTag 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){

str = Pattern.compile("<").matcher(str).replaceAll("&lt");
str = Pattern.compile(">").matcher(str).replaceAll("&gt");

pageContext.getOut().println(str);
pageContext.getOut().println("<br>");
}
}

}

3) 基本思路
package com.atguigu.javaweb.tag;

import java.io.IOException;

import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTag;

public class HelloSimpleTag implements SimpleTag {

private String value;
private String count;

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

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

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

JspWriter out = pageContext.getOut();
int c = 0;

c = Integer.parseInt(count);
for(int i = 0; i < c; i++){
out.print((i + 1) + ": " + value);
out.print("<br>");
}
}

@Override
public JspTag getParent() {
System.out.println("getParent");
return null;
}

@Override
public void setJspBody(JspFragment arg0) {
System.out.println("setJspBody");
}

private PageContext pageContext;

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

@Override
public void setParent(JspTag arg0) {
System.out.println("setParent");
}

}

4)tld文件
<?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>atguigu</short-name>
<!-- 作为 tld 文件的 id, 用来唯一标识当前的 TLD 文件, 多个 tld 文件的 URI 不能重复. 通过 JSP 页面的 taglib
标签的 uri 属性来引用. -->
<uri>http://www.atguigu.com/mytag/core</uri>

<tag>
<name>readerFile</name>
<tag-class>com.atguigu.javaweb.tag.ReadFileTag</tag-class>
<body-content>empty</body-content>

<attribute>
<name>src</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>

<tag>
<name>max</name>
<tag-class>com.atguigu.javaweb.tag.MaxTag</tag-class>
<body-content>empty</body-content>

<attribute>
<name>num1</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>

<attribute>
<name>num2</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>

<!-- 描述自定义的 HelloSimpleTag 标签 -->
<tag>
<!-- 标签的名字: 在 JSP 页面上使用标签时的名字 -->
<name>hello</name>

<!-- 标签所在的全类名 -->
<tag-class>com.atguigu.javaweb.tag.HelloSimpleTag</tag-class>
<!-- 标签体的类型 -->
<body-content>empty</body-content>

<!-- 描述当前标签的属性 -->
<attribute>
<!-- 属性名 -->
<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>

</taglib>

8 带标签内容的自定义标签

1). 若一个标签有标签体:

<atguigu:testJspFragment>abcdefg</atguigu:testJspFragment>

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

2). 若配置了标签含有标签体, 则 JSP 引擎会调用 setJspBody() 方法把 JspFragment 传递给标签处理器类
在 SimpleTagSupport 中还定义了一个 getJspBody() 方法, 用于返回 JspFragment 对象.

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

有时, 可以 借助于 StringWriter, 可以在标签处理器类中先得到标签体的内容:

得到标签体
JspFragment bodyContent=getJspBody();

//1. 利用 StringWriter 得到标签体的内容.
StringWriter sw = new StringWriter();
bodyContent.invoke(sw);

//2. 把标签体的内容都变为大写
String content = sw.toString().toUpperCase();

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

<body-content>: 指定标签体的类型, 大部分情况下, 取值为 scriptless。可能取值有 3 种:
empty: 没有标签体
scriptless: 标签体可以包含 el 表达式和 JSP 动作元素,但不能包含 JSP 的脚本元素
tagdependent: 表示标签体交由标签本身去解析处理。
若指定 tagdependent,在标签体中的所有代码都会原封不动的交给标签处理器,而不是将执行结果传递给标签处理器

<body-content>tagdependent</body-content>

9带父标签的自定义标签

package com;

import java.io.IOException;

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

public class SonTag extends SimpleTagSupport {

@Override
public void doTag() throws JspException, IOException {
System.out.println("运行1");
//1 得到父标签的引用
JspTag parent=getParent();
//2 获取父标签的name属性
ParentTag parentTag=(ParentTag)parent;
String name=parentTag.getName();
//3把name值打印到jsp页面上
getJspContext().getOut().print("子标签输出name"+name);
}

}


package com;

import java.io.IOException;

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

public class ParentTag extends SimpleTagSupport {

private String name="bean";


public String getName()
{
return name;
}
@Override
public void doTag() throws JspException, IOException {
System.out.println("运行2");
System.out.println("父标签标签处理器name"+name);
getJspBody().invoke(null);
}

}


<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="bean" uri="http://www.bean.com/mytag/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<!-- 父标签打印name到控制台 -->
<bean:parentTag>
<!--子标签是父标签的标签体 , 我们让 子标签把父标签的name属性打印到jsp页面上 -->
<bean:sonTag/>
</bean:parentTag>
</body>
</html>


<?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>

<!--建议使用的标签前缀 -->
<short-name>bean</short-name>
<!--作为tld文件的id,用来唯一标识当前的tld文件 多个tld的文件的uri不能重复 通过在JSP页面上的tiglib标签的uri属性进行引用-->
<uri>http://www.bean.com/mytag/core</uri>

<tag>
<name>parentTag</name>
<tag-class>com.ParentTag</tag-class>
<body-content>scriptless</body-content>
</tag>

<tag>
<name>sonTag</name>
<tag-class>com.SonTag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>


1)运行过程中先执行父标签的dotag再执行子标签的dotag
父标签的doTag中需要getJspBody().invoke(null); 这个语句子标签的doTag才能执行
2)父标签无法获取子标签 但是子标签能获取父标签 子标签通过getParent()方法获取父标签

3) 父标签的类型是JspTag 是一个空接口 用来统一SimpleTag和Tag 实际使用需要进行类型的强制转换

4)在tld配置文件中 无需为父标签有额外的配置,但子标签是以标签体的形式存在,所以父标签的bodyContent需要设置为scriptless


10EL自定义函数(我们很少自己写) 在JSTL中定义 简化操作字符串使用
EL中已经给我们定义了很多函数 例如${fn:length{paramname}

那么如何自定义函数呢

1 在一个类中写一个静态方法

2 在tld文件中描述EL自定义函数

 

自定义标签

标签:gui   param   source   list   writer   public   sch   utf-8   包含   

原文地址:http://www.cnblogs.com/HJL085/p/6036413.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!