這兩天公司讓作一個報表,時間比較緊就用以前同事的代碼,以前同事使用的 POI 開發的 , 我在開發的時候感受比較繁瑣,特別是對「細胞」(cell)的設置,若是一個類裏面要處處兩個不一樣的報表,那麼你個組裝過程將會變得異常的煩人, 即便把數據組裝這部分抽取出來感受仍是很繁瑣。下面就給你們推薦一種好的方法使用 XLSTransformer 來導出報表。可能個人語言不夠華美不能打動讓你使用XLSTransformer,下面我們就拿某公司現有的程序作個對比:html
一:使用POI 作的導出:java
java類中的 exportTradeIllegalDetails 方法:apache
/**安全
* 導出excel多線程
* @param parameter 查出來的list集合app
* @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 |
構造方法詳細信息 |
---|
protected ()
默認構造方法受到有意保護。
方法詳細信息 |
---|
public void ()
將此 Transformer
重置爲其初始配置。
Transformer
被重置爲經過 TransformerFactory.newTransformer()、TransformerFactory.newTransformer(Source source) 或 Templates.newTransformer() 建立它時的狀態。reset()
的設計目標是容許重用現有 Transformer
,以節省與建立新 Transformer
有關的資源。
不保證重置的 Transformer
具備相同的 URIResolver 或 ErrorListener Object
,例如 Object.equals(Object obj)。但保證具備功能相同的 URIResolver
和 ErrorListener
。
拋出:
UnsupportedOperationException
- 當實現不能重寫此方法時。
從如下版本開始:
1.5
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
- 若是轉換過程當中發生不可恢復的錯誤。
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。
public abstract Object (String name)
獲取經過 setParameter 顯式設置的參數。
此方法不返回默認參數值,默認參數值直到在轉換過程當中計算了節點上下文後才能肯定。
參數:
name
- 要獲取的 Object
返回:
已經過 setParameter 設置的參數。
public abstract void ()
清除全部經過 setParameter 設置的參數。
public abstract void (URIResolver resolver)
設置將用於解析在 document() 中使用的 URI 的對象。
若是解析器參數爲 null,則將清除 URIResolver 值,且轉換器將再也不擁有解析器。
參數:
resolver
- 實現 URIResolver 接口的對象,或爲 null。
public abstract URIResolver ()
獲取將用於解析在 document() 中使用的 URI 的對象。
返回:
實現 URIResolver 接口的對象,或返回 null。
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
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
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
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
public abstract void (ErrorListener listener) throws IllegalArgumentException
設置轉換的實際錯誤事件偵聽器。
參數:
listener
- 新錯誤偵聽器。
拋出:
IllegalArgumentException
- 若是偵聽器爲 null。
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("成功"); }}