JSP学习笔记(五):自定义标签-JSP1.x

来源:互联网 发布:java条形码生成代码 编辑:程序博客网 时间:2024/05/16 09:25
1、任何一个标签都对应一个Java类,该类必须实现Tag接口。
2、一个标签可以通过 tld 文件查找该标签的是实现类,并运行该类的相关方法。

一、简单标签实现
(一)实现Tag接口
1、实现代码:

<span style="font-family:Arial;">package taglib.jsp_one;import java.io.IOException;import java.util.ResourceBundle;import javax.servlet.jsp.JspException;import javax.servlet.jsp.JspWriter;import javax.servlet.jsp.PageContext;import javax.servlet.jsp.tagext.Tag;/** * * @Title: 实现方式一:实现Tag接口 * @Description: * @Copyright: Copyright (c) 2015 * @Company: * * @author: SAM-SHO * @version: 1.0 * @CreateDate:Feb 16, 2015 */public class Copyright implements Tag {  private Tag parent;//父标签,本例不使用 private PageContext pageContext;//JSP内容 @Override public int doStartTag() throws JspException {//标签开始执行  return SKIP_BODY;//跳过标签体 }  @Override public int doEndTag() throws JspException {//标签结束时执行  JspWriter out = pageContext.getOut(); //获取 out 对象  //输出版权信息  try {   out.println("<div align=center style='line-height: 22px; font-size: 12px; '>");   out.println(ResourceBundle.getBundle("copyright").getString("copyright"));   out.println("</div>");  } catch (IOException e) {   throw new JspException(e);  }  return EVAL_PAGE;//执行标签后的内容 } @Override public Tag getParent() {  return this.parent; } @Override public void release() { } @Override public void setPageContext(PageContext pageContext) {  this.pageContext = pageContext; } @Override public void setParent(Tag parent) {  this.parent = parent; }}// end</span>

1)两个属性:parent 和 pageContext。parent为该标签的父标签,pageContext 为运行该标签的 JSP 页面。

2、tid 标签库描述文件。默认在/WEB-INF/下
<span style="font-family:Arial;"> <tlibversion>1.0</tlibversion> <jspversion>1.1</jspversion> <shortname>myTaglib</shortname> <!--推荐使用的prefix --> <uri>http://www.may_Taglib.com/tags</uri> <!--引用标签的uri --> <info>A simple tab library for the examples</info> <!-- 单个标签配置 --> <tag>  <name>copyright</name><!--标签名-->  <tagclass>taglib.jsp_one.Copyright</tagclass><!--是实现类-->  <bodycontent>JSP</bodycontent><!--标签体的限制,支持标签体-->  <info>Copyright tag.</info> </tag></span>


1)<shortname> :推荐使用的prefix 
2)<uri> :引用标签的uri
3)<tag>:配置某个标签
4)<name>:标签名
5)<tagclass>:是实现类
6)<bodycontent>:标签体的限制。有3种取值:
①、empty:不允许有便签体存在。如果有,执行会抛出异常。
②、JSP:允许有标签体存在。可以是JSP代码。
③、tagdependent:允许有标签体存在,但是标签体内的JSP代码不会被执行。

4、动态指定 tid 文件的路径:在 web.xml 中配置(利用jsp的配置)
<span style="font-family:Arial;">   <taglib>    <taglib-uri>http://www.mayTaglib.com/tags</taglib-uri>    <taglib-location>/WEB-INF/taglib.tld</taglib-location><!--定义tld文件位置 -->   </taglib></span>


(二)方法的调用顺序
1、Tag 接口源码分析
<span style="font-family:Arial;">public interface Tag extends JspTag {     public final static int SKIP_BODY = 0;    public final static int EVAL_BODY_INCLUDE = 1;    public final static int SKIP_PAGE = 5;    public final static int EVAL_PAGE = 6;    void setPageContext(PageContext pc);    void setParent(Tag t);    Tag getParent();     int doStartTag() throws JspException;    int doEndTag() throws JspException;    void release();}</span>

2、执行顺序:



(二)使用TagSupport类
1、多数情况下不需要实现Tag接口,继承TagSupport 类即可。TagSupport 是Java的一个模板类,是实现了pageContext 与parent 的getter 、setter方法以及其他一些功能。需要做的只是根据需要实现 doStartTag() 与doEndTag()方法。

2、实例代码:(tld配置略)
<span style="font-family:Arial;">package taglib.jsp_one;import java.io.IOException;import java.util.ResourceBundle;import javax.servlet.jsp.JspException;import javax.servlet.jsp.JspWriter;import javax.servlet.jsp.tagext.TagSupport;/** * * @Title: 方式二:继承TagSupport 类 * @Description:只要实现 doStartTag 与 doEndTag即可 * @Copyright: Copyright (c) 2015 * @Company: * * @author: SAM-SHO * @version: 1.0 * @CreateDate:Feb 16, 2015 */public class Copyright2 extends TagSupport { private static final long serialVersionUID = -2936770589554413334L; @Override public int doEndTag() throws JspException {  JspWriter out = pageContext.getOut();  try {   out.println("<div align=center style='line-height: 22px; font-size: 12px; '>");   out.println(ResourceBundle.getBundle("copyright").getString("copyright"));   out.println("</div>");  } catch (IOException e) {   throw new JspException(e);  }  return EVAL_PAGE; } @Override public int doStartTag() throws JspException {  return super.doStartTag(); }}// end</span>


(三)支持属性的标签
1、标签的属性是通过 Tag的实现类的 setter 方法注释进去的。因此只需要给标签类增加一个属性以及相应的 setter 方法就可以了。
<span style="font-family:Arial;">package taglib.jsp_one;import javax.servlet.jsp.JspException;import javax.servlet.jsp.tagext.TagSupport;/** * * @Title: 支持属性的标签 * @Description: * @Copyright: Copyright (c) 2015 * @Company: * * @author: SAM-SHO * @version: 1.0 * @CreateDate:Feb 16, 2015 */public class HelloTag extends TagSupport { private static final long serialVersionUID = -8828591126748246256L; private String name;//name属性 @Override public int doEndTag() throws JspException {  try {   this.pageContext.getOut().println("Hello, " + name);  } catch (Exception e) {   throw new JspException(e);  }  return EVAL_PAGE; } public String getName() {  return name; } public void setName(String name) {  this.name = name; }}// end</span>


2、tld文件配置:<attribute> 配置属性
 
<span style="font-family:Arial;"><tag>  <name>hello</name>  <tagclass>taglib.jsp_one.HelloTag</tagclass>  <bodycontent>empty</bodycontent><!--不支持标签体-->  <info>Hello tag with parameters.</info>  <attribute>   <name>name</name><!--name属性-->   <required>true</required><!--该属性为必须的-->   <rtexprvalue>true</rtexprvalue><!--是否允许EL表达式 与 jsp标本-->  </attribute> </tag></span>


二、带标签体的实现

(一)实现BodyTag 接口
1、流程图如下:


1)doStartTag()方法返回值,如果为 EVAL_BODY_INCLUDE,则会直接输出标签体内容;
2)如果为 EVAL_BODY_BUFFERED ,则不会输出,而是将标签体内容通过 setBodyContent()方法注释到标签类里,然后就可以使用 getBodyContent() 方法得到标签体的内容。


(二)继承 BodyTagSupport 类
1、通常都是使用继承 BodyTagSupport 类实现,默认的,BodyTagSupport 类会按照中间的主险一直往下执行。
2、实例:
<span style="font-family:Arial;">package taglib.jsp_one;import javax.servlet.jsp.JspException;import javax.servlet.jsp.tagext.BodyTagSupport;/** * * @Title: 实现标签体的自定义标签,继承BodyTagSupport * @Description: * @Copyright: Copyright (c) 2015 * @Company: * * @author: SAM-SHO * @version: 1.0 * @CreateDate:Feb 16, 2015 */public class ToLowerCaseTag extends BodyTagSupport { private static final long serialVersionUID = -2529343271020971948L; @Override public int doEndTag() throws JspException {  String content = this.getBodyContent().getString();//得到标签体  try {   this.pageContext.getOut().print(content.toLowerCase());//输出  } catch (Exception e) {  }  return EVAL_PAGE; }}// end</span>

<span style="font-family:Arial;"><tag>  <name>toLowerCase</name>  <tagclass>taglib.jsp_one.ToLowerCaseTag</tagclass>  <bodycontent>JSP</bodycontent>  <info>Tag with body.</info> </tag></span>


3、只要在 setBodyContent() 方法之后被调用的方法中,都可以使用 getBodyContent()方法获取标签体的内容。一般为 doEndTag() 和 doAfterBody() 。

(三)多次执行循环标签体
1、单次执行是指标签体只会被使用一次,二多次执行是指标签体可以被使用多次。由流程图可知,可以控制 doAfterBody()方法的返回值,达到单次还是多次的效果。
<span style="font-family:Arial;">package taglib.jsp_one;import javax.servlet.jsp.JspException;import javax.servlet.jsp.tagext.BodyTagSupport;/** * * @Title: 多次循环标签体得标签 * @Description: * @Copyright: Copyright (c) 2015 * @Company: * * @author: SAM-SHO * @version: 1.0 * @CreateDate:Feb 16, 2015 */public class LoopTag extends BodyTagSupport { private static final long serialVersionUID = 5882067091737658241L; private int times; @Override public int doStartTag() throws JspException {  times = 5;  return super.doStartTag(); }  @Override public int doAfterBody() throws JspException {  if (times-- > 0) {   /** 只要 times > 0 就继续循环,同时 times 自减 */   try {    //在 doAfterBody() 方法内输出是写入到 BodyContent缓存中,    //因此每次 getBodyContent()取出的值都会递增    this.getPreviousOut().println(this.getBodyContent().getString()+"<br/>");   } catch (Exception e) {   }   return EVAL_BODY_AGAIN;//返回值EVAL_PAGE ,则执行单次  } else {//小心死循环   /** 结束运行,同时复原 times */   times = 5;   return SKIP_BODY;//结束  } }}// end</span>

<span style="font-family:Arial;"> <tag>  <name>loop</name>  <tagclass>taglib.jsp_one.LoopTag</tagclass>  <bodycontent>JSP</bodycontent>  <info>Tag with body.</info> </tag></span>


三、复杂标签
(一)动态参数的标签:实现 DynamicAttributes 接口
1、标签类代码:
<span style="font-family:Arial;">package taglib.jsp_one;import java.util.HashMap;import java.util.Map;import java.util.Map.Entry;import javax.servlet.jsp.JspException;import javax.servlet.jsp.JspWriter;import javax.servlet.jsp.tagext.DynamicAttributes;import javax.servlet.jsp.tagext.TagSupport;/** * * @Title: 动态属性的标签 * @Description: * @Copyright: Copyright (c) 2015 * @Company: * * @author: SAM-SHO * @version: 1.0 * @CreateDate:Feb 17, 2015 */public class DynamicAttributeTag extends TagSupport implements DynamicAttributes { private static final long serialVersionUID = -1477571708507488373L; private Map<String, Double> map = new HashMap<String, Double>();//动态参数的容器 @Override public int doEndTag() throws JspException {  JspWriter out = pageContext.getOut();  double min = 0, max = 0;  for (Double d : map.values()) {   min = Math.min(d, min);   max = Math.max(d, max);  }  StringBuffer buffer = new StringBuffer();  buffer.append("<table>");  for (Entry<String, Double> entry : map.entrySet()) {   buffer.append("<tr>");   buffer.append("<td>" + entry.getKey() + "</td>");   buffer.append("<td><img src='../../images/vote.gif' height='10' width='");   buffer.append((entry.getValue() - min) / (max - min + 1) * 200 + 50);   buffer.append("' /> " + entry.getValue() + "</td>");   buffer.append("</tr>");  }  buffer.append("</table>");  try {   out.write(buffer.toString());  } catch (Exception e) {  }  return super.doEndTag(); } //自动会注释动态参数 @Override public void setDynamicAttribute(String uri, String key, Object value) throws JspException {  map.put(key, Double.parseDouble((String) value)); }}// end</span>


2、tld文件配置:
 
<span style="font-family:Arial;"><tag>  <name>dynamicAttribute</name>  <tagclass>taglib.jsp_one.DynamicAttributeTag</tagclass>  <bodycontent>empty</bodycontent>  <dynamic-attributes>true</dynamic-attributes><!-- 配置动态属性 -->  <info>Tag with dynamic attribute.</info> </tag></span>


(二)嵌套自定义标签
1、标签代码:
1)父标签
<span style="font-family:Arial;">package taglib.jsp_one.table;import java.io.IOException;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;import java.util.Map;import javax.servlet.http.HttpServletRequest;import javax.servlet.jsp.JspException;import javax.servlet.jsp.JspWriter;import javax.servlet.jsp.tagext.BodyContent;import javax.servlet.jsp.tagext.BodyTagSupport;/** * * @Title: 嵌套父标签:Table标签 * @Description: * @Copyright: Copyright (c) 2015 * @Company: * * @author: SAM-SHO * @version: 1.0 * @CreateDate:Feb 16, 2015 */public class Table extends BodyTagSupport { private static final long serialVersionUID = 3358444196409845360L; /** 存储列信息 */ private List<Map<String, String>> columns = new ArrayList<Map<String, String>>(); /** 存储数据,可能为 集合类型的或者数组类型的 */ private Object items; /** 取排序数据的 URL */ private String url; @Override public int doStartTag() throws JspException {  columns.clear();//每次清空  return super.doStartTag(); } @Override public int doAfterBody() throws JspException {  try {   BodyContent bc = getBodyContent();   JspWriter out = bc.getEnclosingWriter();   HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();   /** 按哪一列排序 */   String orderName = request.getParameter("orderName");   /** 按升序还是降序排序 */   String orderType = request.getParameter("orderType");   orderType = "desc".equals(orderType) ? "desc" : "asc";   out.println("<table id=theObjTable");   out.println(" class=list_table STYLE='table-layout:fixed;' >");   out.println(" <tr class=tr_title>");   out.println(" <script>var columns = []; </script>");   for (int i = 0; i < columns.size(); i++) {    /** 获取列信息 */    Map<String, String> column = columns.get(i);    /** 列头 */    String label = column.get("label");    /** 该列对应的 Java Bean 的属性 */    String property = column.get("property");    label = label == null ? property : label;    out.println("<td id='__id_td_" + property + "'>");    out.println("<font class='resizeDivClass'");    out.println(" onmousedown='MouseDownToResize(this);');");    out.println(" onmousemove='MouseMoveToResize(this);'");    out.println(" onmouseup='MouseUpToResize(this);'></font>");    out.println("<span onclick=\"sort('" + property + "'); \"");    out.println(" style=\"cursor: pointer; \">");    out.println(label);    if (property.equals(orderName)) {     out.println("<img src='../../images/" + orderType + ".gif' border=0/>");    }    out.println("</span>");    out.println("</td>");    out.println("<script>columns[columns.length] = '__id_td_" + property + "'; </script>");   }   out.println(" </tr>");   if (items != null) {    /** 遍历所有的数据 */    for (Object obj : (Iterable) items) {     out.println(" <tr class=tr_data>");     for (int i = 0; i < columns.size(); i++) {      Map<String, String> column = columns.get(i);      String property = column.get("property");      String getterStyle = toGetterStyle(property);      try {       String getter = "get" + getterStyle;       String is = "is" + getterStyle;       Method method = null;       try {        /** 获取 getXxx() 形式的方法 */        method = obj.getClass().getMethod(getter);       } catch (Exception e) {       }       if (method == null) {        /** 如果没有,获取 isXxx() 形式的方法 */        method = obj.getClass().getMethod(is);       }       method.setAccessible(true);       /** 获取属性值 */       Object value = method.invoke(obj);       out.println("<td><span title='" + value + "'>" + value + "</span></td>");      } catch (Exception e) {       throw new JspException(e);      }     }     out.println(" </tr>");    }   }   out.println("</table>");   out.println("<script>");   out.println(" var orderName = '" + orderName + "'; ");   out.println(" var orderType = '" + orderType + "'; ");   out.println(" function sort(column){");   out.println(" if(orderName == column){");   out.println(" location='" + url + "?orderName=' + column + '&orderType=' + (orderType=='asc' ? 'desc' : 'asc'); ");   out.println(" }");   out.println(" else{");   out.println(" location='" + url + "?orderName=' + column + '&orderType=' + orderType; ");   out.println(" }");   out.println(" }");   out.println("</script>");  } catch (IOException ioe) {   throw new JspException("Error: " + ioe.getMessage());  }  return SKIP_BODY; } public Object getItems() {  return items; } public void setItems(Object items) {  this.items = items; } /**  * 首字母大写  *  * @param column  * @return  */ public String toGetterStyle(String column) {  if (column.length() == 1)   return column.toUpperCase();  char ch = column.charAt(0);  return Character.toUpperCase(ch) + column.substring(1); } public List<Map<String, String>> getColumns() {  return columns; } public void setColumns(List<Map<String, String>> columns) {  this.columns = columns; } public String getUrl() {  return url; } public void setUrl(String url) {  this.url = url; }}</span>

<span style="font-family:Arial;"> <tag>  <name>table</name>  <tagclass>taglib.jsp_one.table.Table</tagclass>  <bodycontent>JSP</bodycontent>  <info>Table tag.</info>  <attribute>   <name>items</name>   <required>true</required>   <rtexprvalue>true</rtexprvalue>  </attribute>  <attribute>   <name>url</name>   <required>false</required>   <rtexprvalue>true</rtexprvalue>  </attribute> </tag></span>


2)子标签:
<span style="font-family:Arial;">package taglib.jsp_one.table;import java.util.HashMap;import java.util.Map;import javax.servlet.jsp.JspException;import javax.servlet.jsp.tagext.TagSupport;/** * * @Title: Column 标签 * @Description: * @Copyright: Copyright (c) 2015 * @Company: * * @author: SAM-SHO * @version: 1.0 * @CreateDate:Feb 16, 2015 */public class Column extends TagSupport { private static final long serialVersionUID = 5119493903438602864L; private String property; private String label; private String type; public int doStartTag() throws JspException {  if (!(this.getParent() instanceof Table)) {   throw new JspException("Column must be inside Table. ");  }  Map<String, String> column = new HashMap<String, String>();  column.put("label", label);  column.put("property", property);  column.put("type", type);  Table table = (Table) this.getParent();  table.getColumns().add(column);  return SKIP_BODY; } public int doEndTag() throws JspException {  return EVAL_PAGE; } public String getProperty() {  return property; } public void setProperty(String property) {  this.property = property; } public String getLabel() {  return label; } public void setLabel(String label) {  this.label = label; } public String getType() {  return type; } public void setType(String type) {  this.type = type; }}</span>

<span style="font-family:Arial;"><tag>  <name>column</name>  <tagclass>taglib.jsp_one.table.Column</tagclass>  <bodycontent>empty</bodycontent>  <info>Column tag.</info>  <attribute>   <name>property</name>   <required>true</required>   <rtexprvalue>true</rtexprvalue>  </attribute>  <attribute>   <name>label</name>   <required>false</required>   <rtexprvalue>true</rtexprvalue>  </attribute> </tag></span>


调用标签jsp代码:

<span style="font-family:Arial;"><%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>  <%@ taglib uri="http://www.mayTaglib.com/tags" prefix="myTaglib"%><!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>Base JSP</title></head><body><myTaglib:copyright>Hello, myTaglib</myTaglib:copyright><myTaglib:toLowerCase>变成全部小写:HELLO,SAM</myTaglib:toLowerCase><br/><myTaglib:loop>loop> </myTaglib:loop><br/><myTaglib:dynamicAttribute a="1" b="2" /><br/></body></html></span>




0 0
原创粉丝点击