一、背景
當(dāng)前b/s模式已成為應(yīng)用開發(fā)的主流,而在企業(yè)辦公系統(tǒng)中,常常有客戶這樣子要求:你要把我們的報表直接用excel打開(電信系統(tǒng)、銀行系統(tǒng))。或者是:我們已經(jīng)習(xí)慣用excel打印。這樣在我們實際的開發(fā)中,很多時候需要實現(xiàn)導(dǎo)入、導(dǎo)出excel的應(yīng)用。
最近在java上做了一個excel的導(dǎo)出功能,寫了一個通用類,在這里分享分享,該類支持多sheet,且無需手動進行復(fù)雜的類型轉(zhuǎn)換,只需提供三個參數(shù)即可:
1、filename
excel文件名
2、hasmap<string,list<?>> data
具體的數(shù)據(jù),每個list代表一張表的數(shù)據(jù),?表示可為任意的自定義對象
3、linkedhashmap<string,string[][]> headers
stirng代表sheet名。每個string[][]代表一個sheet的定義,舉個例子如下:
1
2
3
4
5
|
string[][] header = { { "field1" , "參數(shù)1" } ,{ "field2" , "參數(shù)2" } ,{ "field3" , "參數(shù)3" } } |
其中的field1,field2,field3為對象中的屬性名,參數(shù)1,參數(shù)2,參數(shù)3為列名,實際上這個指定了列的名稱和這個列用到數(shù)據(jù)對象的哪個屬性。
二、怎么用
以一個例子來說明怎么用,假設(shè)有兩個類a和b定義如下:
1
2
3
4
5
6
7
8
9
|
public class a{ private string name; private string address; } public class b{ private int id; private double sum; private string cat; } |
現(xiàn)在我們通過查詢數(shù)據(jù)庫獲得了a和b的兩個列表:
list<a> dataa = .....;
list<b> datab = .....;
我們將這兩個導(dǎo)出到excel中,首先需要定義sheet:
1
2
3
4
5
6
7
8
9
|
string[][] sheeta = { { "name" , "姓名" } ,{ "address" , "住址" } } string[][] sheetb = { { "id" , "id" } ,{ "sum" , "余額" } ,{ "cat" , "貓的名字" } } |
然后將數(shù)據(jù)匯總構(gòu)造一個excelutil:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
string filename = "測試excel" ; hashmap<string,list<?>> data = new hashmap<>(); //asheet為表名,后面headers里的key要跟這里一致 data.put( "asheet" ,dataa); data.put( "bsheet" ,datab); linkedhashmap<string,string[][]> headers = new linkedhashmap<>(); headers.put( "asheet" ,sheeta); headers.put( "bsheet" ,sheetb); excelutil excelutil = new excelutil(filename,data,headers); //獲取表格對象 hssfworkbook workbook = excelutil.createexcel(); //這里內(nèi)置了一個寫到response的方法(判斷瀏覽器類型設(shè)置合適的參數(shù)),如果想寫到文件也是類似的 workbook.writetoresponse(workbook,request,response); |
當(dāng)然通常數(shù)據(jù)是通過數(shù)據(jù)庫查詢的,這里為了演示方便沒有從數(shù)據(jù)庫查找。
三、實現(xiàn)原理
這里簡單說明下實現(xiàn)過程,從調(diào)用createexcel()這里開始
1、遍歷headers創(chuàng)建sheet
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public hssfworkbook createexcel() throws exception { try { hssfworkbook workbook = new hssfworkbook(); //遍歷headers創(chuàng)建表格 for (string key : headers.keyset()) { this .createsheet(workbook, key, headers.get(key), this .data.get(key)); } return workbook; } catch (exception e) { log.error( "創(chuàng)建表格失敗:{}" , e.getmessage()); throw e; } } |
將workbook,sheet名,表頭數(shù)據(jù),行數(shù)據(jù)傳入cratesheet方法中創(chuàng)建sheet。
2、創(chuàng)建表頭
表頭也就是一個表格的第一行,通常用來對列進行說明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
hssfsheet sheet = workbook.createsheet(sheetname); // 列數(shù) int cellnum = header.length; // 單元行,單元格 hssfrow row; hssfcell cell; // 表頭單元格樣式 hssfcellstyle columntopstyle = this .getcolumntopstyle(workbook); // 設(shè)置表頭 row = sheet.createrow( 0 ); for ( int i = 0 ; i < cellnum; i++) { cell = row.createcell(i); cell.setcellstyle(columntopstyle); string str = header[i][ 1 ]; cell.setcellvalue(str); // 設(shè)置列寬為表頭的文字寬度+6個半角符號寬度 sheet.setcolumnwidth(i, (str.getbytes( "utf-8" ).length + 6 ) * 256 ); } |
3、插入行數(shù)據(jù)
這里是最重要的部分,首先通過數(shù)據(jù)的類對象獲取它的反射屬性field類,然后將屬性名和field做一個hash映射,避免循環(huán)查找,提高插入速度,接著通過一個switch語句,根據(jù)屬性類別設(shè)值,主要代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
/** * 設(shè)置單元格,根據(jù)fieldname獲取對應(yīng)的field類,使用反射得到值 * * @param cell 單元格實例 * @param obj 存有屬性的對象實例 * @param fieldmap 屬性名與field的映射 * @param fieldname 屬性名 */ private void setcell(hssfcell cell, object obj, map<string, field> fieldmap, string fieldname) throws exception { //獲取該屬性的field對象 field field = fieldmap.get(fieldname); //通過反射獲取屬性的值,由于不能確定該值的類型,用下面的判斷語句進行合適的轉(zhuǎn)型 object value = field.get(obj); if (value == null ) { cell.setcellvalue( "" ); } else { switch (field.getgenerictype().gettypename()) { case "java.lang.string" : cell.setcellvalue((string) value); break ; case "java.lang.integer" : case "int" : cell.setcellvalue(( int ) value); break ; case "java.lang.double" : case "double" : cell.setcellvalue(( double ) value); break ; case "java.util.date" : cell.setcellvalue( this .dateformat.format((date) value)); break ; default : cell.setcellvalue(obj.tostring()); } } } |
完整代碼可以到github上查看下載,這里就不列出來了。
github地址:點擊跳轉(zhuǎn)
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對服務(wù)器之家的支持。
原文鏈接:https://www.cnblogs.com/wuyoucao/p/9526620.html