这两天公司让做一个报表,时间比较紧就用之前同事的代码,之前同事使用的 POI 开发的 , 我在开发的时候感觉比较繁琐,特别是对“细胞”(cell)的设置,如果一个类里面要到处两个不同的报表,那么你个组装过程将会变得异常的烦人, 即使把数据组装这部分抽取出来感觉还是很繁琐。下面就给大家推荐一种好的方法使用 XLSTransformer 来导出报表。可能我的语言不够华美不能打动让你使用XLSTransformer,下面咱们就拿某公司现有的程序做个对比:
一:使用POI 做的导出:
java类中的 exportTradeIllegalDetails 方法:
/**
* 导出excel
* @param parameter 查出来的list集合
* @param outputStream
* @throws IOException
*/
public void exportTradeIllegalDetails(List<Map<String,Object>> parameter,ServletOutputStream outputStream) throws IOException {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("余额变动明细" );
String[] headerColumns={ "操作日期" ,"用户id" ,"姓名" ,"手机号" ,"订单号" ,"解冻/冻结" ,"余额变动" ,"帐号余额" ,"项目明细" ,"项目明细内容" };
ExcelUtil. generateHeader(workbook ,sheet,headerColumns);
HSSFCellStyle style = ExcelUtil. getCellStyle(workbook,false);
int rowNum = 0;
for(Map<String,Object> r : parameter){
rowNum++;
Row row = sheet.createRow(rowNum);
row.setHeightInPoints(25);
// 操作日期
int i=0;
Cell cell = row.createCell(i++);
cell.setCellStyle(style);
cell.setCellValue(disposeStrNull(r.get( "time")));
//用户id 要加密
cell = row.createCell(i++);
cell.setCellStyle(style);
cell.setCellValue(disposeStrNull(r.get( "uid")));
//姓名
cell = row.createCell(i++);
cell.setCellStyle(style);
cell.setCellValue(disposeStrNull(r.get( "userName")));
//手机号
cell = row.createCell(i++);
cell.setCellStyle(style);
cell.setCellValue(disposeStrNull(r.get( "mobile")));
if(r.get("orderNo" )!=null && !r.get("orderNo" ).toString().equals("")){
//订单号
cell = row.createCell(i++);
cell.setCellStyle(style);
cell.setCellValue(disposeStrNull(r.get( "orderNo")));
} else if(r.get("contractCode" )!=null && !r.get("contractCode" ).toString().equals("")){
//合同号
cell = row.createCell(i++);
cell.setCellStyle(style);
cell.setCellValue(disposeStrNull(r.get( "contractCode")));
} else{
cell = row.createCell(i++);
cell.setCellStyle(style);
cell.setCellValue( "");
}
//解冻/冻结
cell = row.createCell(i++);
cell.setCellStyle(style);
if(disposeStrNull(r.get( "type")).equals("3" )||disposeStrNull(r.get( "type")).equals("0" )){
cell.setCellValue(disposeStrNull(r.get( "amount")));
} else{
cell.setCellValue( "0");
}
//余额变动
cell = row.createCell(i++);
cell.setCellStyle(style);
if(disposeStrNull(r.get( "type")).equals("1" )||disposeStrNull(r.get( "type")).equals("2" )){
cell.setCellValue(disposeStrNull(r.get( "amount")));
} else{
cell.setCellValue( "0");
}
//帐号余额
cell = row.createCell(i++);
cell.setCellStyle(style);
cell.setCellValue(disposeStrNull(r.get( "totalAmount")));
//项目明细
cell = row.createCell(i++);
cell.setCellStyle(style);
cell.setCellValue(disposeStrNull(r.get( "proDetail")));
//项目明细内容
cell = row.createCell(i++);
cell.setCellStyle(style);
cell.setCellValue(disposeStrNull(r.get( "proConDetail")));
}
workbook.write(outputStream);
outputStream.flush();
outputStream.close();
}
ExcelUtil:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
/**
* excel操作工具类
*
* @param <T>
*/
public class ExcelUtil {
public static HSSFCellStyle getCellStyle(HSSFWorkbook workbook,boolean isHeader){
HSSFCellStyle style = workbook.createCellStyle();
style.setBorderBottom(HSSFCellStyle.BORDER_THIN );
style.setBorderLeft(HSSFCellStyle.BORDER_THIN );
style.setBorderRight(HSSFCellStyle.BORDER_THIN );
style.setBorderTop(HSSFCellStyle.BORDER_THIN );
style.setLocked( true);
if (isHeader) {
style.setFillForegroundColor(HSSFColor.GREY_25_PERCENT.index);
style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND );
HSSFFont font = workbook.createFont();
font.setColor(HSSFColor.BLACK.index );
font.setFontHeightInPoints((short ) 12);
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD );
style.setFont(font);
}
return style;
}
public static void generateHeader(HSSFWorkbook workbook,HSSFSheet sheet,String[] headerColumns){
HSSFCellStyle style = getCellStyle(workbook,true);
Row row = sheet.createRow(0);
row.setHeightInPoints(30);
for(int i=0;i<headerColumns.length ;i++){
Cell cell = row.createCell(i);
String[] column = headerColumns[i].split("_#_" );
if(column.length ==1){
sheet.setColumnWidth(i, 3000);
} else{
sheet.setColumnWidth(i, Integer.valueOf(column[1]));
}
cell.setCellValue(column[0]);
cell.setCellStyle(style);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static <T> HSSFSheet creatAuditSheet(HSSFWorkbook workbook,String sheetName,
List<T> dataset,String[] headerColumns,String[] fieldColumns) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
HSSFSheet sheet = workbook.createSheet(sheetName);
sheet.protectSheet( "");
generateHeader(workbook,sheet,headerColumns);
HSSFCellStyle style = getCellStyle(workbook,false);
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd" );
int rowNum = 0;
for(T t:dataset){
rowNum++ ;
Row row = sheet.createRow(rowNum);
row.setHeightInPoints(25);
for(int i = 0; i < fieldColumns.length; i++){
String fieldName = fieldColumns[i] ;
String getMethodName = "get" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
try {
Class clazz = t.getClass();
Method getMethod;
getMethod = clazz.getMethod(getMethodName, new Class[]{} );
Object value = getMethod.invoke(t, new Object[]{});
String cellValue = "";
if (value instanceof Date){
Date date = (Date)value;
cellValue = sd.format(date);
} else{
cellValue = null != value ? value.toString() : "" ;
}
Cell cell = row.createCell(i);
cell.setCellStyle(style);
cell.setCellValue(cellValue);
} catch (Exception e) {
}
}
}
return sheet;
}
}
如果现在又有一个新的报表需求并且和之前的半毛钱关系都没有的话,那么你将重复的写这三行代码
cell = row.createCell(i++); cell.setCellStyle(style); cell.setCellValue(disposeStrNull(r.get("uid")));
可能你抽取的更多代码可能会少点,如果报表的很多的话,这些依然很繁琐!下面就让 XLSTransformer 展示展示他的威力吧
二:XLSTransformer导出
2.1 ) 在使用之前,我们先学习一下Transformer 这个类吧
javax.xml.transform
类 Transformer
java.lang.Object [object Object]
public abstract class
extends Object
此抽象类的实例能够将源树转换为结果树。
可以通过 TransformerFactory.newTransformer 方法获取此类的实例。然后可以使用此实例处理来自不同源的 XML,并将转换输出写入各种接收器。
在多线程同时运行时不能使用此类的对象。不同线程可以同时使用不同的 Transformers。
Transformer
可以多次使用。可以在转换之间保留参数和输出属性。
构造方法摘要 | |
---|---|
protected | Transformer() 默认构造方法受到有意保护。 |
方法摘要 | |
---|---|
abstract void | clearParameters() 清除所有通过 setParameter 设置的参数。 |
abstract ErrorListener | getErrorListener() 获取转换的实际错误事件处理程序。 |
abstract Properties | getOutputProperties() 获取转换的输出属性的副本。 |
abstract String | getOutputProperty(String name) 获取对转换器有效的输出属性。 |
abstract Object | getParameter(String name) 获取通过 setParameter 显式设置的参数。 |
abstract URIResolver | getURIResolver() 获取将用于解析在 document() 中使用的 URI 的对象。 |
void | reset() 将此 Transformer 重置为其初始配置。 |
abstract void | setErrorListener(ErrorListener listener) 设置转换的实际错误事件侦听器。 |
abstract void | setOutputProperties(Properties oformat) 设置转换的输出属性。 |
abstract void | setOutputProperty(String name, String value) 设置转换中实际的输出属性。 |
abstract void | setParameter(String name, Object value) 添加一个转换参数。 |
abstract void | setURIResolver(URIResolver resolver) 设置将用于解析在 document() 中使用的 URI 的对象。 |
abstract void | transform(Source xmlSource, Result outputTarget) 将 XML Source 转换为 Result 。 |
从类 java.lang.Object 继承的方法 |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
构造方法详细信息 |
---|
Transformer
protected ()
默认构造方法受到有意保护。
方法详细信息 |
---|
reset
public void ()
将此
Transformer
重置为其初始配置。Transformer
被重置为通过 TransformerFactory.newTransformer()、TransformerFactory.newTransformer(Source source) 或 Templates.newTransformer() 创建它时的状态。reset()
的设计目标是允许重用现有Transformer
,以节省与创建新Transformer
有关的资源。不保证重置的
Transformer
具有相同的 URIResolver 或 ErrorListenerObject
,例如 Object.equals(Object obj)。但保证具有功能相同的URIResolver
和ErrorListener
。抛出:
UnsupportedOperationException
- 当实现不能重写此方法时。从以下版本开始:
1.5
transform
public abstract void (Source xmlSource,
Result outputTarget)
throws TransformerException
将 XML
Source
转换为Result
。当实例化Transformer
和对Transformer
实例进行任何修改时,指定的转换行为由TransformerFactory
的实际设置决定。空
Source
表示为由 DocumentBuilder.newDocument() 构造的空文档。空Source
的转换结果取决于转换行为;结果不总为空Result
。参数:
xmlSource
- 要转换的 XML 输入。outputTarget
- 转换xmlSource
的Result
。抛出:
TransformerException
- 如果转换过程中发生不可恢复的错误。
setParameter
public abstract void (String name,
Object value)
添加一个转换参数。
以两部分字符串形式传递限定名称,即用花括号括起来的名称空间 URI,后跟本地名称。如果名称中有 null URL,则 String 只包含本地名称。应用程序可以通过测试安全地检查非 null URI,以查看名称的首字符是否为 '{' 字符。
例如,如果 URI 和本地名称是从通过 <xyz:foo xmlns:xyz="http://xyz.foo.com/yada/baz.html"/> 定义的元素获取的,则限定名称将为 "{http://xyz.foo.com/yada/baz.html}foo"。注意,不使用前缀。
参数:
name
- 参数名称,它可以以花括号({})中的名称空间 URI 开始。value
- 值对象。它可以为任何有效的 Java 对象。处理器负责提供正确的对象 coersion,或只传递在扩展中使用的对象。抛出:
NullPointerException
- 如果值为 null。
getParameter
public abstract Object (String name)
获取通过 setParameter 显式设置的参数。
此方法不返回默认参数值,默认参数值直到在转换过程中计算了节点上下文后才能确定。
参数:
name
- 要获取的Object
返回:
已通过 setParameter 设置的参数。
clearParameters
public abstract void ()
清除所有通过 setParameter 设置的参数。
setURIResolver
public abstract void (URIResolver resolver)
设置将用于解析在 document() 中使用的 URI 的对象。
如果解析器参数为 null,则将清除 URIResolver 值,且转换器将不再拥有解析器。
参数:
resolver
- 实现 URIResolver 接口的对象,或为 null。
getURIResolver
public abstract URIResolver ()
获取将用于解析在 document() 中使用的 URI 的对象。
返回:
实现 URIResolver 接口的对象,或返回 null。
setOutputProperties
public abstract void (Properties oformat)
设置转换的输出属性。这些属性将重写通过 xsl:output 在 Templates 中设置的属性。
如果此函数的参数为 null,则移除任何以前设置的属性,且值将恢复为 templates 对象中定义的值。
以两部分字符串形式传递限定属性,即用花括号括起来的名称空间 URI,后跟本地名称。如果名称中有 null URL,则 String 只包含本地名称。应用程序可以通过测试安全地检查非 null URI,以查看名称的首字符是否为 '{' 字符。
例如,如果 URI 和本地名称是从通过 <xyz:foo xmlns:xyz="http://xyz.foo.com/yada/baz.html"/> 定义的元素获取的,则限定名称将为 "{http://xyz.foo.com/yada/baz.html}foo"。注意,不使用前缀。
如果任何参数键不能被识别且不是名称空间限定的,则抛出
IllegalArgumentException
。参数:
oformat
- 将用于重写在实际转换中任何相同属性的输出属性集。抛出:
IllegalArgumentException
- 当键无法识别且不是限定于名称空间的键时。另请参见:
OutputKeys, Properties
getOutputProperties
public abstract Properties ()
获取转换的输出属性的副本。
返回的属性应包含由用户设置的属性,以及通过样式表设置的属性,且这些属性将 section 16 of the XSL Transformations (XSLT) W3C Recommendation 指定的默认属性作为“默认值”。由用户或通过样式表特定设置的属性应位于基本 Properties 列表中,而未特定设置的 XSLT 默认属性应位于默认的 Properties 列表中。因此,getOutputProperties().getProperty(String key) 将包含通过 setOutputProperty(java.lang.String, java.lang.String)、setOutputProperties(java.util.Properties) 设置的任何属性,或者在样式表或 默认属性中设置的任何属性,而 getOutputProperties().get(String key) 将只检索通过 setOutputProperty(java.lang.String, java.lang.String)、setOutputProperties(java.util.Properties) 显式设置的属性,或在样式表中显式设置的属性。
注意返回的 Properties 对象的变化将不影响转换器所包含的属性。
如果任何参数键不能被识别且不是名称空间限定的键,则属性将被忽略且不返回。换句话说,行为与 setOutputProperties 无关。
返回:
下一个实际转换中的输出属性集的副本。
另请参见:
OutputKeys, Properties, XSL Transformations (XSLT) Version 1.0
setOutputProperty
public abstract void (String name,
String value)
throws IllegalArgumentException
设置转换中实际的输出属性。
以两部分字符串形式传递限定属性名称,即用花括号括起来的名称空间 URI,后跟本地名称。如果名称中有 null URL,则 String 只包含本地名称。应用程序可以通过测试安全地检查非 null URI,以查看名称的首字符是否为 '{' 字符。
例如,如果 URI 和本地名称是从通过 <xyz:foo xmlns:xyz="http://xyz.foo.com/yada/baz.html"/> 定义的元素获取的,则限定名称将为 "{http://xyz.foo.com/yada/baz.html}foo"。注意,不使用前缀。
传递给 setOutputProperties(java.util.Properties) 的 Properties 对象不会受到调用此方法的影响。
参数:
name
- 指定了输出属性名称的非 null String,它可以是名称空间限定的。value
- 输出属性的非 null 字符串值。抛出:
IllegalArgumentException
- 如果不支持属性,且该属性没有限定于某一名称空间。另请参见:
OutputKeys
getOutputProperty
public abstract String (String name)
throws IllegalArgumentException
获取对转换器有效的输出属性。
如果已经使用 setOutputProperty(java.lang.String, java.lang.String) 设置了属性,则返回所设置的值。如果在样式表中显式地指定了属性,则返回所指定的值。如果使用默认属性值,即没有使用 setOutputProperty(java.lang.String, java.lang.String) 或在样式表中显式地设置了任何值,则结果将随实现以及输入样式表而改变。
参数:
name
- 指定了输出属性名称的非 null String,它可以是名称空间限定的。返回:
输出属性的字符串值,如果找不到属性,则返回 null。
抛出:
IllegalArgumentException
- 如果不支持属性。另请参见:
OutputKeys
setErrorListener
public abstract void (ErrorListener listener)
throws IllegalArgumentException
设置转换的实际错误事件侦听器。
参数:
listener
- 新错误侦听器。抛出:
IllegalArgumentException
- 如果侦听器为 null。
getErrorListener
public abstract ErrorListener ()
获取转换的实际错误事件处理程序。实现必须提供默认错误侦听器。
返回:
当前错误处理程序,它永远不应为 null。
2.2 ) 学习完Transformer 这个类我们就来写一个Demo试试手吧!
package com.jhaso.action;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.jxls.exception.ParsePropertyException;
import net.sf.jxls.transformer.XLSTransformer;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Workbook;
import com.jhaso.model.ContReportModel;
import com.jhaso.util.ExportImportUtil;
import com.jhaso.util.FormatUtil;
public class AgeContAction {
public ContReportModel am = new ContReportModel();
public String contCode;
private static String PATH = "D:/work/jhaso/JXLTest/src/com/jhaso/template/jxls_agent_report.xls";
private static String PATH2 = "D:/work/jhaso/JXLTest/src/com/jhaso/template/";
private static List<ContReportModel> list;
public AgeContAction(){
init();
}
private void init() {
list = new ArrayList<ContReportModel>();
ContReportModel crm = new ContReportModel();
crm.setIndex(1);
crm.setOperTimeView("2015-08-01 00:00:00");
crm.setName("铁臂金刀");
crm.setRecharge(1000.00);
crm.setMargin(2000.00);
crm.setRebate(3560.00);
crm.setRefund(4560.00);
crm.setCosts(3560.00);
crm.setOperContent("铁臂金刀向郑州一百度充值");
list.add(crm);
ContReportModel crm2 = new ContReportModel();
crm2.setIndex(2);
crm2.setOperTimeView("2015-08-01 00:00:00");
crm2.setName("铁臂阿童木");
crm2.setRecharge(1500.00);
crm2.setMargin(2500.00);
crm2.setRebate(3860.00);
crm2.setRefund(5590.00);
crm2.setCosts(4560.00);
crm2.setOperContent("铁臂阿童木向郑州一百度充值");
list.add(crm2);
}
/**
* 导出excel
*/
public void toReportExcel(HttpServletRequest request, HttpServletResponse response) {
// 导出数据
String srcFilePath = PATH;
String destFilePath = ExportImportUtil.getDataTempFile(
PATH2).getAbsoluteFile()
+ File.separator + new Date().getTime() + "_report.xls";
File detFile = new File(destFilePath);
InputStream iputStream;
try {
iputStream = new FileInputStream(new File(PATH));
Map<String,Object> beanParams = new HashMap<String,Object>();
beanParams.put("operat", list);
XLSTransformer transformer = new XLSTransformer();
Workbook wb = (Workbook) transformer.transformXLS(iputStream, beanParams);
/*
* 真实项目请打开注释
* response.setHeader(
"Content-Disposition",
"attachment;fileName="+ ExportImportUtil.generateFileName(request,FormatUtil.formatDate() + "合同报表.xls"));
response.setContentType("application/vnd.ms-excel");*/
OutputStream os = response.getOutputStream();
wb.write(new FileOutputStream(destFilePath)); // 导出Excel
os.flush();
iputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ParsePropertyException e) {
e.printStackTrace();
} catch (InvalidFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
detFile.delete();
System.out.println("成功");
}
}