单位里的查询系统是基于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"/>
还没有在标签里做分页的处理,以后在加工吧