单位里的查询系统是基于struts的,在结果集显示的处理上都是用 <logic:iterate id=".." indexId="id" name=".." scope="request"> 然后在<bean:write name=".." property=".."> 这样子对付的,后来觉得比较麻烦,就写了一个显示结果集的标签
- 行记录用HashMap保存
- 结果集用Vector封装
- 表格的标题等属性用xml配置
- dom4j解析xml文件
- 输出时根据配置合并多行内的相同属性列
- 求和
表格配置文件table-config.xml保存在/WEB-INF下


<?xml version="1.0" encoding="gb2312"?>
<table-config>


<table name="jcgl_dzjk" width="800">
<title>稽查数据电子缴库情况</title>
<groupby>id_wjdm</groupby>
<columns>
<column>
<name>id_wjdm</name>
<header>微机代码</header>
<width>60</width>
<bind>true</bind>
</column>
<column>
<name>name_nsr</name>
<header>单位名称</header>
<width>200</width>
<bind>true</bind>
</column>
<column>
<name>id_sz</name>
<header>税种</header>
<map>map_sz</map>
</column>
<column>
<name>id_sm</name>
<header>税目</header>
</column>
<column>
<name>ybtse</name>
<header>查补金额</header>
<width>100</width>
<sum>true</sum>
</column>
<column>
<name>date_sbbrq</name>
<header>申报日期</header>
</column>
<column>
<name>date_jkrq</name>
<header>扣款日期</header>
</column>
<column>
<name>kkzt</name>
<header>扣款状态</header>
</column>
</columns>
</table>


</table-config>

用于表格配置的Table.java
package tax.tags;

import java.util.Vector;


public class Table
{
private String name;
private String width;
private String title;
private String groupby;
private Vector<Column> columns;

public Table()
{
}

public Table(String name)
{
this.name=name;
}

public Vector<Column> getColumns()
{
return columns;
}

public void setColumns(Vector<Column> columns)
{
this.columns = columns;
}

public String getName()
{
return name;
}

public void setName(String name)
{
this.name = name;
}

public String getTitle()
{
return title;
}

public void setTitle(String title)
{
this.title = title;
}

public String getWidth()
{
return width;
}

public void setWidth(String width)
{
this.width = width;
}

public String getGroupby()
{
return groupby;
}

public void setGroupby(String groupby)
{
this.groupby = groupby;
}

public String toString()
{
StringBuffer buf=new StringBuffer();
buf.append("Name:").append(name).append("\n");
buf.append("Width:").append(width).append("\n");
buf.append("Title:").append(title).append("\n");
buf.append("Groupby:").append(groupby).append("\n");

for(int i=0;i<columns.size();i++)
{
Column column=columns.elementAt(i);
buf.append("column name:").append(column.getName()).append("\n");
buf.append(" header:").append(column.getHeader()).append("\n");
buf.append(" width:").append(column.getWidth()).append("\n");
buf.append(" sum:").append(column.isSum()).append("\n");
buf.append(" bind:").append(column.isBind()).append("\n");
}
return buf.toString();
}
}




class Column
{
private String name;
private String width;
private String header;
private String map;
private boolean sum;
private boolean bind;


public Column()
{
sum=false;
bind=false;
}

public boolean isBind()
{
return bind;
}

public void setBind(boolean bind)
{
this.bind = bind;
}

public String getHeader()
{
return header;
}

public void setHeader(String header)
{
this.header = header;
}

public String getName()
{
return name;
}

public void setName(String name)
{
this.name = name;
}

public boolean isSum()
{
return sum;
}

public void setSum(boolean sum)
{
this.sum = sum;
}

public String getWidth()
{
return width;
}

public void setWidth(String width)
{
this.width = width;
}

public String getMap()
{
return map;
}

public void setMap(String map)
{
this.map = map;
}
}


用dom4j解析table-config.xml的Dom4jTable.java,因为用到了xpath,所以把jaxen-1.1-beta-6.jar也要拷贝到/web-inf/lib里面去
package tax.tags;

import java.util.List;
import java.util.Vector;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;


public class Dom4jTable
{
String tableName;


public Dom4jTable()
{ }


public Dom4jTable(String tableName)
{
this.tableName = tableName;
}


public Document parse(String xmlpath) throws DocumentException
{
SAXReader reader = new SAXReader();
Document doc = null;
doc = reader.read(xmlpath);
return doc;
}


public Table getTable(Document doc)
{
Table table;
String xpath = "//table[@name='" + tableName + "']";
Node node = doc.selectSingleNode(xpath);

if (node == null)
{
table = null;

} else
{
table = new Table(tableName);
table.setWidth(getValue(node,"@width"));
table.setTitle(getValue(node,"title"));
table.setGroupby(getValue(node,"groupby"));
Vector<Column> columns = new Vector<Column>();
Node nodeColumns = node.selectSingleNode("columns");
List list = ((Element) nodeColumns).elements();

for (int i = 0; i < list.size(); i++)
{
Column column = new Column();
Element element = (Element) list.get(i);
column.setName(getValue(element,"name"));
column.setHeader(getValue(element,"header"));
column.setWidth(getValue(element,"width"));
column.setMap(getValue(element,"map"));
column.setBind(Boolean.parseBoolean(getValue(element,"bind")));
column.setSum(Boolean.parseBoolean(getValue(element,"sum")));
columns.add(column);
}
table.setColumns(columns);
}
return table;
}

private String getValue(Node node,String name)
{
String value=node.valueOf(name);

if(value.equals(""))
{
value=null;
}
return value;
}
}


自定义标签ShowTableTag.java,写的有点乱,还好能用,本来用sax解析xml的,后来改为dom4j的
package tax.tags;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.Vector;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;


public class ShowTableTag extends TagSupport
{
private static final long serialVersionUID = 1L;

private Log log = LogFactory.getLog(this.getClass());

private String vectorName;

private String tableName;

private boolean displaySN = false;

private Vector<HashMap> data = null;


public int doStartTag() throws JspException
{
return TagSupport.SKIP_BODY;
}


public int doEndTag() throws JspException
{
String newline = "\n";
boolean getsum=false;
JspWriter out = pageContext.getOut();
StringBuffer buf = new StringBuffer();

if (data == null || data.size() == 0)
{
buf.append("There is no result available.");

} else
{
// 取表格的各项属性设置
Table table = getTableConfigByDom4j();
// 取表格的各列,然后存入cols数组
Vector columns = table.getColumns();
Column[] cols=new Column[columns.size()];
BigDecimal[] sum=new BigDecimal[columns.size()];

for(int i=0;i<columns.size();i++)
{
cols[i]=(Column)columns.elementAt(i);
if(cols[i].isSum()) getsum=true;
sum[i]=new BigDecimal(0);
}
/////////////////////////////////////////////////////////////////////////////////////////
// 如果table没有设置title, 就不打印这部分

if(table.getTitle()!=null)
{
buf.append("<DIV id=tag_head><div class=label>").append(newline);
buf.append(table.getTitle()).append("</div></div><div id=tag_body>");
buf.append(newline);
}
buf.append("<div class=content>").append(newline);
buf.append("<table border=1 cellPadding=0 cellSpacing=0 ");
buf.append("borderColorLight=#000000 borderColorDark=#f8f7f5 width=\"");
buf.append(table.getWidth()).append("\">").append(newline);
buf.append("<tr class=tablehead>").append(newline);
// 如果标签中的displaySN为true, 则打印序号列

if (displaySN)
{
buf.append("<th>序号</th>").append(newline);
}

// 打印table的th栏

for (int i = 0; i < cols.length; i++)
{
buf.append("<th");

if (cols[i].getWidth() != null)
{
buf.append(" width=").append(cols[i].getWidth());
}
buf.append(">").append(cols[i].getHeader()).append("</th>");
buf.append(newline);
}
buf.append("</tr>").append(newline);


// 由table的groupby属性产生key_group<Integer,Integer>
// 第一个Integer是行号,从1开始
// 第二个Integer是跨度span,即连续相同的key的数量
Hashtable key_group = getKeyGroup(table.getGroupby());
int rowid = 0; //行号
int distid = 0; //捆绑相同key行后的行号
Iterator<HashMap> it = data.iterator();

while (it.hasNext())
{
buf.append("<tr class=tablepad>").append(newline);
rowid++;
// 根据行号从key_group中取得pan值, span可能为null
Integer span=(key_group==null?null:(Integer)key_group.get(new Integer(rowid)));

// 显示序号

if (displaySN)
{

if(key_group==null)
{
//key_group为null表示table中不用合并相同的行
buf.append("<td>").append(rowid).append("</td>");

}else if(span!=null)
{
buf.append("<td rowspan=").append(span).append(">");
buf.append(++distid).append("</td>").append(newline);
}
}
// 取得这一行的记录
HashMap row = (HashMap)it.next();

for (int i = 0; i < cols.length; i++)
{
// 取得td中应该显示的内容
String td = (String) row.get(cols[i].getName());

if(cols[i].isSum())
{
sum[i]=sum[i].add(new BigDecimal(td));
}

if(cols[i].getMap()!=null)
{
TreeMap map = (TreeMap) pageContext.getServletContext()
.getAttribute(cols[i].getMap());
td=(String)map.get(td);
}
if (td == null) td = " ";
// 区别这个列的bind属性确定是否要合并显示

if(!cols[i].isBind()||key_group==null)
{
buf.append("<td>");
buf.append(td).append("</td>").append(newline);

}else if(span!=null)
{
buf.append("<td rowspan=").append(span).append(">");
buf.append(td).append("</td>").append(newline);
}
}
buf.append("</tr>").append(newline);
}
//如果需要打印合计数,增加一行

if(getsum)
{
buf.append("<tr class=tablepad>");

if(displaySN)
{
buf.append("<td> </td>");
}

for(int i=0;i<cols.length;i++)
{

if(cols[i].isSum())
{
buf.append("<td>").append(sum[i]).append("</td>").append(newline);

}else
{
buf.append("<td> </td>").append(newline);
}
}
buf.append("</tr>").append(newline);
}
buf.append("</table>").append(newline);
buf.append("</div></div>");
}

try
{
out.println(buf.toString());

} catch (Exception e)
{
log.error("e");
return TagSupport.SKIP_PAGE;
}
return TagSupport.EVAL_PAGE;
}



private Hashtable getKeyGroup(String key)
{
if(key==null) return null;
// 返回Hashtable, 键-从1开始的行号. 值-从这行开始连续的rowspan值.
Hashtable<Integer, Integer> ht = new Hashtable<Integer, Integer>();
Iterator it = data.iterator();
int count = 0;
int start = 0;
int current = 0;
String value = "", prevalue = "";


while (it.hasNext())
{
current++;
HashMap row = (HashMap) it.next();
value = (String) row.get(key);
if (value.equals(prevalue))
count++;

else
{
ht.put(new Integer(start),new Integer(count));
prevalue = value;
count = 1;
start=current;
}
}
ht.put(new Integer(start),new Integer(count));
ht.remove(new Integer(0));
return ht;
}


private Table getTableConfigBySax()
{
Table table = null;
SaxTable sax = new SaxTable();
sax.setTableName(tableName);
String xmlfile = pageContext.getServletContext().getRealPath(
"WEB-INF/table-config.xml");

try
{
XMLReader xdr = XMLReaderFactory
.createXMLReader("org.apache.xerces.parsers.SAXParser");
xdr.setContentHandler(sax);
xdr.parse(xmlfile);

} catch (Exception e)
{
log.error(e);
}
table = sax.getTable();
return table;
}


private Table getTableConfigByDom4j()
{
Dom4jTable dt = new Dom4jTable(tableName);
Document doc = null;
String xmlPath = pageContext.getServletContext().getRealPath(
"WEB-INF/table-config.xml");

try
{
doc = dt.parse(xmlPath);

} catch (DocumentException e)
{
log.error(e);
return null;
}
Table table = dt.getTable(doc);
return table;
}

public String getTableName()
{
return this.tableName;
}


public void setTableName(String tableName)
{
this.tableName = tableName;
}


public String getVectorName()
{
return this.vectorName;
}


public void setVectorName(String vectorName)
{
this.vectorName = vectorName;
Object o = pageContext.getRequest().getAttribute(vectorName);

if (o != null)
{
data = (Vector<HashMap>) o;

} else
{
data = null;
}
}


public void setDisplaySN(boolean sn)
{
displaySN = sn;
}


public boolean isDisplaySN()
{
return displaySN;
}
}


在标签库app.tld中的这一段tag定义
<tag>
<name>showTable</name>
<tagclass>tax.tags.ShowTableTag</tagclass>
<bodycontent>empty</bodycontent>
<info>
extract the date from a vector and present date in table
</info>
<attribute>
<name>vectorName</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>tableName</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>displaySN</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>

最后就可以在jsp文件中使用了,例如:
<app:showTable tableName="jcgl_dzjk" vectorName="data" displaySN="true"/>
还没有在标签里做分页的处理,以后在加工吧