用java完成將數據導出到Excel中的功能,首先去了解一下有哪些Java ExcelAPI。
Java Aspose Cells
Java Aspose Cells 是一種純粹的Java授權的Excel API,開發和供應商Aspose發布。這個API的最新版本是8.1.2,發布於2014年7月,是一個豐富而厚重的API(普通Java類和AWT類的組合)設計,可以讀、寫和操縱電子表格Excel的組件。此API常見用途如下:
- Excel報表,建立動態Excel報表
- 高保真的Excel渲染和打印
- 從Excel電子表格中導入和導出數據
- 生成,編輯,轉換和電子表格
JXL
JXL是一款專為Selenium第三方框架,支持基於Web瀏覽器(數據是Web瀏覽器自動更新)數據驅動的自動化。然而,它也被用來作為JExcel API的一個共同的支持庫,因為它的基本功能是可創建,讀取和寫入電子表格。基本特征如下:
- 生成Excel文件
- 從工作簿和電子表格導入數據
- 獲得行和列的總數
- 注意:JXL只支持xls檔案格式,並且不能處理大數據量。
JExcel
JExcel是由Team Dev開發提供純行貨API。利用這一點程序員可以很容易地讀取,寫入,顯示和修改Excel工作簿中的兩種格式:.xls和.XLSX。這個API可以很容易地嵌入Java的Swing和AWT。這個API的最新版本是Jexcel-2.6.12,發布於2009年,主要特點如下:
- 自動化Excel應用程序,工作簿,工作表等
- 在Java Swing應用程序作為普通的Swing組件嵌入到工作簿
- 事件偵聽器添加到工作簿和電子表格
- 添加事件處理程序來處理的工作簿和電子表格事件的行為
- 添加本地對等開發定制功能
Apache POI
Apache POI是Apache軟件基金會提供的100%開源庫。大多數中小規模的應用程序開發主要依賴於Apache POI(HSSF+ XSSF)。它支持Excel 庫的所有基本功能; 然而,呈現和文本提取是它的主要特點。
這次我用到的是最后一種Apache POI。首先是一個總的方法exportExcel_2007,傳入4個主要參數,分別是: sheetName 工作表的名稱;dataset 數據源;fieldMap 類的英文屬性和Excel中的中文列名的對應關系;sheetSize 每個工作表中記錄的最大個數。
代碼如下:
/**
* @param sheetName 工作表的名稱
* @param dataset 數據源
* @param fieldMap 類的英文屬性和Excel中的中文列名的對應關系
* @param sheetSize 每個工作表中記錄的最大個數
* @return
* @throws Exception
*/
public <T> Workbook exportExcel_2007(String sheetName, List<T> dataset,
LinkedHashMap<String, String> fieldMap, int sheetSize, List<ModelAttr> modelAttrs) throws Exception {
if(dataset==null || dataset.size()==0) {
throw new RuntimeException("沒有任何數據");
}
SXSSFWorkbook wb = new SXSSFWorkbook(1000);
//1.計算一共有多少個工作表
double sheetNum = Math.ceil(dataset.size()/new Integer(sheetSize).doubleValue());
//2.創建相應的工作表,並向其中填充數據
for(int i=0; i<sheetNum; i++){
//如果只有一個工作表的情況
if(1==sheetNum){
Sheet sheet = wb.createSheet(sheetName);
fillSheet(sheet, dataset, fieldMap, 0, dataset.size()-1,modelAttrs);
setColumnBorderAndColor(wb,sheet);
//有多個工作表的情況
}else{
Sheet sheet = wb.createSheet(sheetName+(i+1));
//獲取開始索引和結束索引
int firstIndex=i*sheetSize;
int lastIndex=(i+1)*sheetSize-1>dataset.size()-1 ? dataset.size()-1 : (i+1)*sheetSize-1;
//填充工作表
fillSheet(sheet, dataset, fieldMap, firstIndex, lastIndex,modelAttrs);
setColumnBorderAndColor(wb,sheet);
}
}
return wb;
}
將工作表創建出來,就需要對表頭和表體進行填充。因為我這里的表頭是動態的,因此多傳入了一個參數進行相關判斷。填充表頭和表體的函數是fillSheet。
代碼如下:
/**
* @MethodName : fillSheet
* @Description : 向工作表中填充數據
* @param sheet 工作表
* @param list 數據源
* @param fieldMap 中英文字段對應關系的Map
* @param firstIndex 開始索引
* @param lastIndex 結束索引
*/
private <T> void fillSheet(
Sheet sheet,
List<T> list,
LinkedHashMap<String,String> fieldMap,
int firstIndex,
int lastIndex,
List<ModelAttr> modelAttrs
)throws Exception{
//定義存放英文字段名和中文字段名的數組
String[] enFields=new String[fieldMap.size()];
String[] cnFields=new String[fieldMap.size()];
//填充數組
int count=0;
for(Map.Entry<String,String> entry:fieldMap.entrySet()){
enFields[count]=entry.getKey();
cnFields[count]=entry.getValue();
count++;
}
//填充表頭
Row firstRow = sheet.createRow(0);
for(int i=0;i<cnFields.length;i++){
firstRow.createCell(i).setCellValue(cnFields[i]);
}
//填充內容
int rowNo=1;
for(int index=firstIndex;index<=lastIndex;index++){
Row row = sheet.createRow(rowNo);
//獲取單個對象
Map<String,Object> item= (Map<String, Object>) list.get(index);
for(int i=0;i<enFields.length;i++){
ModelAttrType type = null;
for(ModelAttr modelAttr : modelAttrs){
if(enFields[i].equals(modelAttr.getAttrCode())){
type = modelAttr.getAttrType();
}
}
String value = getFieldValueByNameSequence(enFields[i], item,type);
String fieldValue=value==null ? "" : value;
row.createCell(i).setCellValue(fieldValue);
}
rowNo++;
}
//設置自動列寬
setColumnAutoSize(sheet, 512);
}
首先將表頭的數據放入兩個數組中,一個是中文表頭,一個是英文code,用來匹配表體。然后中文表體填充到新建的firstRow中。
在表頭完成后,根據數據源填充表體,因為數據源是一個復雜的mapList,所以需要對填充的value進行提取處理。我這里寫了幾個方法,其中針對不同類型的數據處理寫了一個感知器,感知器的不用類型處理的代碼太多,就不貼了。總之能把你想要放的數據取出來就可以,不用寫很復雜。
代碼如下:
/**
* @MethodName : getFieldValueByNameSequence
* @Description :
* 根據屬性名獲取屬性值
*
* @param fieldNameSequence 簡單屬性名
* @param o 對象
* @return 屬性值
* @throws Exception
*/
private String getFieldValueByNameSequence(String fieldNameSequence, Map<String,Object> o,ModelAttrType type) throws Exception{
String value=null;
return value = getFieldValueByName(fieldNameSequence,o,type);
}
/**
* @MethodName : getFieldValueByName
* @Description : 根據字段名獲取字段值
* @param fieldName 字段名
* @param o 對象
* @return 字段值
*/
private String getFieldValueByName(String fieldName, Map<String,Object> o,ModelAttrType type) throws Exception{
Object value=null;
value=getFieldByName(fieldName, o);
String valueStr = insAttrValueAwareProcessor.convertToExcel(type, value);
return valueStr;
}
/**
* @MethodName : getFieldByName
* @Description : 根據字段名獲取字段
* @param fieldName 字段名
* @param
* @return 字段
*/
private static Object getFieldByName(String fieldName, Map<String,Object> o){
if(o == null){
return null;
}
return o.get(fieldName);
}
填充完數據后,就需要簡單設置一下工作表的樣式,具體看實際情況。
代碼如下:
/**
* @MethodName : setColumnAutoSize
* @Description : 設置工作表自動列寬和首行加粗
* @param ws
*/
private static void setColumnAutoSize(Sheet ws,int extraWith){
//獲取本列的最寬單元格的寬度
for(int i=0;i<ws.getRow(0).getPhysicalNumberOfCells();i++){
int colWith=0;
for(int j=0;j<ws.getLastRowNum();j++){
String content=ws.getRow(j).getCell(i).getStringCellValue();
int cellWith=content.length();
if(colWith<cellWith){
colWith=cellWith;
}
}
//設置單元格的寬度為最寬寬度+額外寬度
ws.setColumnWidth(i, colWith*extraWith);
}
}
/**
* 設置工作表單元格邊框和首行背景色
* @param wb
* @param ws
*/
private static void setColumnBorderAndColor(SXSSFWorkbook wb,Sheet ws){
XSSFCellStyle cellBorderStyle = (XSSFCellStyle)wb.createCellStyle();
XSSFCellStyle cellColorStyle = (XSSFCellStyle)wb.createCellStyle();
for(int i=0;i<ws.getPhysicalNumberOfRows();i++){
Row row = ws.getRow(i);
for(int j=0;j<ws.getRow(0).getPhysicalNumberOfCells();j++){
Cell cell = row.getCell(j);
Cell cellFirst = ws.getRow(0).getCell(j);
//給單元格設置邊框
cellBorderStyle.setBorderBottom(BorderStyle.THIN);
cellBorderStyle.setBorderTop(BorderStyle.THIN);
cellBorderStyle.setBorderLeft(BorderStyle.THIN);
cellBorderStyle.setBorderRight(BorderStyle.THIN);
//給第一行設置邊框和背景
cellColorStyle.setFillForegroundColor(IndexedColors.AQUA.getIndex());
cellColorStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellColorStyle.setBorderBottom(BorderStyle.THIN);
cellColorStyle.setBorderTop(BorderStyle.THIN);
cellColorStyle.setBorderLeft(BorderStyle.THIN);
cellColorStyle.setBorderRight(BorderStyle.THIN);
cell.setCellStyle(cellBorderStyle);
cellFirst.setCellStyle(cellColorStyle);
}
}
}
有想深入了解學習Apache POI的,可以看看這篇教程Apache POI教程。我也對其進行了參考學習。