需求来源:通常在页面要用表格Table来枚举一个Collection<Object>的某一个属性,如此,势必要在一个TR行显示多个对象。
必要性: 一般可以在页面通过Java代码来循环,而且此时需要判断Collection的对象个数能否被列数整除,不能整除的要分为前N-1行和第N行,比较复杂且不容易改动,如下:
<%
String savePath = "/phssas-web/jsp/upload/report-data/";
File[] reptFiles = FileOperator.orderByLastModified(application.getRealPath(savePath), 2);
int len = reptFiles==null ? 0 : reptFiles.length;
int lines = len%2==0 ? len/2 : (len/2+1);
for (int i=0; i<lines-1; i++){ //前N-1行全部输出
%>
<tr height="25"><td width="50%"> <!-- 一旦不是分两列,则需要调整 -->
<a href="download.jsp?fileName=<%=savePath+reptFiles[2*i].getName()%>"><%=reptFiles[2*i].getName()%></a>
</td><td>
<a href="download.jsp?fileName=<%=savePath+reptFiles[2*i+1].getName()%>"><%=reptFiles[2*i+1].getName()%></a>
</td></tr>
<%
}
out.println("<tr height='25'>");
for (int i=2*(lines-1); i<len; i++){ //第N行不完整
%>
<td width="50%">
<a href="download.jsp?fileName=<%=savePath+reptFiles[i].getName()%>"><%=reptFiles[i].getName()%></a>
</td>
<%
}
out.println("<td colspan='"+(2*lines-len)+"'> </td>");
out.println("</tr>");
%>
标签的功能:自动完成上面的布局,只需改变参数columns就自动适应1~m列的情况。
tld描述:
<tag>
<name>table</name>
<tagclass>com.tsinghuatec.dawn.waf.view.taglibs.list.TableListTag</tagclass>
<attribute>
<name>collectionId</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>scope</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>cols</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>td</name>
<tagclass>com.tsinghuatec.dawn.waf.view.taglibs.list.TdItemTag</tagclass>
<attribute>
<name>property</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>attris</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
实现代码:TableListTag
package com.tsinghuatec.dawn.waf.view.taglibs.list;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;
import com.tsinghuatec.dawn.waf.view.taglibs.notag.PageScope;
/**
* @author 熊水林
* Company 北京同方电子有限公司
* @version 1.2
* Created 2006-11-09
*
* <p>descript:这个标签跟ListTag不一样,它不仅要列举对象的Collection,而且要关心
* 表格的"TR"布局</p>
*/
public class TableListTag extends BodyTagSupport {
private String collectionId = null;
private String scope = null;
private int cols = 1;
private Iterator iterator = null;
private Object currentItem = null;
private int index = 0;
private int len = 0;
public int doStartTag() throws JspTagException {
Collection collection = null;
PageScope pageScope = new PageScope(pageContext);
Object targetObject = pageScope.getAttributeInScope(scope,collectionId);
if (targetObject == null) {
throw new JspTagException("TableListTag: Collection " + collectionId + " not found in " + scope + " scope.");
}else if (targetObject instanceof java.util.Collection) {
collection = (Collection)targetObject;
}else {
throw new JspTagException("TableListTag: Iterator " + collectionId + " is not an instance of java.util.Collection.");
}
len = collection.size();
int lines = len%cols==0 ? len/cols : (len/cols+1);
iterator = collection.iterator();
if (!iterator.hasNext()){
return(SKIP_BODY);
}else{
currentItem = iterator.next();
return EVAL_BODY_BUFFERED;
}
}
public int doAfterBody() {
if (!iterator.hasNext()){
return SKIP_BODY;
}else{
index ++;
currentItem = iterator.next();
return super.EVAL_BODY_AGAIN;// EVAL_BODY_BUFFERED;
}
}
public int doEndTag() throws JspTagException {
try{
BodyContent body = getBodyContent();
if (body != null) {
JspWriter out = body.getEnclosingWriter();
out.print(body.getString());
}
reset();
}catch(IOException ioe) {
System.err.println("Error handling items tag: " + ioe);
}
reset();
return EVAL_PAGE;
}
private void reset(){
collectionId = null;
scope = null;
currentItem = null;
index = 0;
}
/*给子标签传递循环对象*/
public Object getCurrentItem() {
return currentItem;
}
public int newLine(){
if (index == 0){
return 0;
}else if ((index+1)%cols == 0){ //tr
return 1;
}else if (!iterator.hasNext()){ //list end, append blank td
int colspan = cols - (len%cols);
if (colspan == 1) colspan = 2;
return colspan;
}else{
return -1;
}
}
public void setCollectionId(String collectionId) {
this.collectionId = collectionId;
}
public void setCols(int cols) {
this.cols = cols;
}
public int getCols(){
return this.cols;
}
public void setScope(String scope) {
this.scope = scope;
}
}
---------------------------
package com.tsinghuatec.dawn.waf.view.taglibs.list;
import java.util.Properties;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.JspWriter;
import com.tsinghuatec.dawn.waf.util.Tools;
/**
* @author 熊水林
* Company 北京同方电子有限公司
* @version 1.2
* Created 2006-11-09
* <p>description: 列出TableListTag.Collection的一个属性,并用TD表示出来,eg.
* width HTML tag:
* <waf:td><a href="test.jsp?id=${this.id}">${this.name}</a></waf:td>
* single text:
* <waf:td property="name" attris="align='center'"/>
* </p>
*/
public class TdItemTag extends BodyTagSupport {
private String property = null; //not required
private String tdAttrs = null; //not required
private TableListTag ancestor;
private Object item = null;
public int doStartTag() throws JspTagException{
ancestor = (TableListTag)findAncestorWithClass(this, TableListTag.class);
if (ancestor == null) {
throw new JspTagException("TdItemTag: TdItemTag 标签不在 TableList 里面");
}
item = ancestor.getCurrentItem();
if (item == null) {
throw new JspTagException("TdItemTag: There is no item to list.");
}
return EVAL_BODY_BUFFERED;
}
public int doEndTag() throws JspTagException {
int newLine = ancestor.newLine();
StringBuffer tdhtml = new StringBuffer();
String bc = analyBodyContent() + getText();
if (ancestor.getCols() == 1){
tdhtml.append("<tr>/n");
tdhtml.append(Tools.isNull(tdAttrs) ? " <td>" : (" <td "+tdAttrs+">"));
tdhtml.append(bc+"</td>/n");
tdhtml.append("</tr>/n");
}else{
if (newLine == 0){ //第一个TD
tdhtml.append("<tr>/n");
}
tdhtml.append(Tools.isNull(tdAttrs) ? " <td>" : (" <td "+tdAttrs+">"));
tdhtml.append(bc+"</td>/n");
if (newLine > 0){
if (newLine == 1){
tdhtml.append("</tr><tr>/n");
}else{//多余的列
tdhtml.append(" <td colspan='"+newLine+"'> </td></tr>");
}
}
}
try{
JspWriter out = pageContext.getOut();
out.print(tdhtml);
}catch(Exception e){
e.printStackTrace();
throw new JspTagException("TdItemTag: Error printing attribute: "+property);
}
return EVAL_PAGE;
}
private String analyBodyContent(){
String bc = bodyContent.getString();
int startIndex = bc.indexOf("${this.") + "${this.".length();
int endIndex = bc.indexOf("}", startIndex);
String propName, propValue=" ";
while (startIndex!=6 && endIndex>startIndex){
propName = bc.substring(startIndex, endIndex);
try{
propValue = Tools.invokeGetMethod(item,propName).toString();
}catch(Exception e){
e.printStackTrace();
}
bc = Tools.replaceStr(bc, "${this."+propName+"}", propValue);
startIndex = bc.indexOf("${this.") + "${this.".length();
endIndex = bc.indexOf("}", startIndex);
}
return bc;
}
private String getText(){
if (Tools.isNull(property)) return "";
if (item instanceof Properties){
return ((Properties)item).getProperty(property, "");
}else{
String value = "";
try{
value = Tools.outObject(Tools.invokeGetMethod(item, property));
}catch(Exception e){
e.printStackTrace();
}
return value;
}
}
public void setProperty(String property) {
this.property = property;
}
public void setAttris(String tdAttrs) {
this.tdAttrs = tdAttrs;
}
}
-------------------------------------------------------------------
测试页面test.jsp(列举当前目录下所有文件名称)
<%@page contentType="text/html;charset=gb2312" isELIgnored="true"%>
<%@taglib uri="/WEB-INF/waftags.tld" prefix="waf"%>
<%@page import="java.io.File, com.tsinghuatec.dawn.waf.util.FileOperator"%>
<%
File[] reptFiles = FileOperator.orderByLastModified(application.getRealPath(""), 2);
request.setAttribute("files", com.tsinghuatec.dawn.waf.util.DataTypeConverter.constructList(reptFiles));
%>
<table width="90%" border="1">
<waf:table cols="2" collectionId="files" scope="request">
<waf:td attris="align='center'"><a href="test.jsp?url=${this.absolutePath}">${this.name}</a></waf:td>
</waf:table>
</table>