什么會寫Easypoi
以前的以前(歲月真TMD的快)我雖然寫了不少代碼但還是很少寫poi,然后跳到一家公司之后就和業務人員聊上了,來這個需要個報表,這個報表樣式是這樣的,這個表頭是這樣的,就這樣我寫了大量的poi代碼,每次都是大量的篇幅,copy to copy,無聊的一逼,然后加入了jeecg,jeecg中有一個小的工具類,雖然我也不知道是誰寫的,然是可以用注解搞定最簡單的導出,突然豁然開朗,我可以完善,讓我從報表的苦海當中脫離出來,這樣我花了一周的時間做了第一個版本支持導入導出放到了jeecg,發現還是不錯的,慢慢的用的人越來越多,我就把這塊獨立出來了,再然后有人提出了模板,然后就加入了模板功能,提出了word的需求,加入了word的功能,后來工作忙了雖然沒再參與jeecg,但還是一直維持這easypoi的更新,根據見識的增長也不斷的重構這代碼,直到現在
獨特的功能
小白如何開始
Easypoi 為誰而開發
都可以使用easypoi
Easypoi的目標是什么
Easypoi的目標不是替代poi,而是讓一個不懂導入導出的快速使用poi完成Excel和word的各種操作,而不是看很多api才可以完成這樣工作
1.3 使用
如果不使用spring mvc的便捷福利,直接引入easypoi-base 就可以了,easypoi-annotation
1.4 測試項目
測試這個事情真不是個容易的事情
測試項目包括兩塊 Junit 的常見測試和spring 的view測試
1.spring view測試
運行application就可以了,訪問界面,然后看到界面
對應的代碼在view下面
2.Junit的測試目錄結構如下
目前的測試覆蓋率
2. Excel 注解版
2.1 Excel導入導出
Excel的導入導出是Easypoi的核心功能,前期基本也是圍繞這個打造的,主要分為三種方式的處理,其中模板和Html目前只支持導出,因為支持Map.class其實導入應該是怎樣都支持的
下面分別就這三種方式進行講解
2.2 注解
注解介紹
easypoi起因就是Excel的導入導出,最初的模板是實體和Excel的對應,model--row,filed--col 這樣利用注解我們可以和容易做到excel到導入導出
經過一段時間發展,現在注解有5個類分別是
注解中的ID的用法
這個ID算是一個比較獨特的例子,比如
@ExcelTarget("teacherEntity") public class TeacherEntity implements java.io.Serializable { /** name */ @Excel(name="主講老師_teacherEntity,代課老師_absent", orderNum="1", mergeVertical=true,needMerge=true,isImportField="true_major,true_absent") private String name;
這里的@ExcelTarget 表示使用teacherEntity這個對象是可以針對不同字段做不同處理
同樣的ExcelEntity 和ExcelCollection 都支持這種方式
當導出這對象時,name這一列對應的是主講老師,而不是代課老師還有很多字段都支持這種做法
@Excel
這個是必須使用的注解,如果需求簡單只使用這一個注解也是可以的,涵蓋了常用的Excel需求,需要大家熟悉這個功能,主要分為基礎,圖片處理,時間處理,合并處理幾塊,name_id是上面講的id用法,這里就不累言了
屬性類型默認值功能name
String
null
列名,支持name_id
needMerge
boolean
fasle
是否需要縱向合并單元格(用于含有list中,單個的單元格,合并list創建的多個row)
orderNum
String
"0"
列的排序,支持name_id
replace
String[]
{}
值得替換 導出是{a_id,b_id} 導入反過來
savePath
String
"upload"
導入文件保存路徑,如果是圖片可以填寫,默認是upload/className/ IconEntity這個類對應的就是upload/Icon/
type
int
1
導出類型 1 是文本 2 是圖片,3 是函數,10 是數字 默認是文本
width
double
10
列寬
height
double
10
列高,后期打算統一使用@ExcelTarget的height,這個會被廢棄,注意
isStatistics
boolean
fasle
自動統計數據,在追加一行統計,把所有數據都和輸出
這個處理會吞沒異常,請注意這一點
isHyperlink
boolean
false
超鏈接,如果是需要實現接口返回對象
isImportField
boolean
true
校驗字段,看看這個字段是不是導入的Excel中有,如果沒有說明是錯誤的Excel,讀取失敗,支持name_id
exportFormat
String
""
導出的時間格式,以這個是否為空來判斷是否需要格式化日期
importFormat
String
""
導入的時間格式,以這個是否為空來判斷是否需要格式化日期
format
String
""
時間格式,相當于同時設置了exportFormat 和 importFormat
databaseFormat
String
"yyyyMMddHHmmss"
導出時間設置,如果字段是Date類型則不需要設置 數據庫如果是string 類型,這個需要設置這個數據庫格式,用以轉換時間格式輸出
numFormat
String
""
數字格式化,參數是Pattern,使用的對象是DecimalFormat
imageType
int
1
導出類型 1 從file讀取 2 是從數據庫中讀取 默認是文件 同樣導入也是一樣的
suffix
String
""
文字后綴,如% 90 變成90%
isWrap
boolean
true
是否換行 即支持\n
mergeRely
int[]
{}
合并單元格依賴關系,比如第二列合并是基于第一列 則{0}就可以了
mergeVertical
boolean
fasle
縱向合并內容相同的單元格
fixedIndex
int
-1
對應excel的列,忽略名字
isColumnHidden
boolean
false
導出隱藏列
@ExcelTarget
限定一個到處實體的注解,以及一些通用設置,作用于最外面的實體
屬性類型默認值功能value
String
null
定義ID
height
double
10
設置行高
fontSize
short
11
設置文字大小
@ExcelEntity
標記是不是導出excel 標記為實體類,一遍是一個內部屬性類,標記是否繼續穿透,可以自定義內部id
屬性類型默認值功能id
String
null
定義ID
@ExcelCollection
一對多的集合注解,用以標記集合是否被數據以及集合的整體排序
屬性類型默認值功能id
String
null
定義ID
name
String
null
定義集合列名,支持nanm_id
orderNum
int
0
排序,支持name_id
type
Class<?>
ArrayList.class
導入時創建對象使用
@ExcelIgnore
忽略這個屬性,多使用需循環引用中,無需多解釋吧^^
2.3 注解導出,導入
2.3.1 對象定義
注解介紹了這么多,大家基本上也了解我們的注解是如何定義Excel的了吧,下面我們來跟著路飛實戰吧
這天老師吧路飛叫到了辦公室,讓給給老師實現一個報表的需求,就是從教育平臺把某個班級的人員導出來
需求是,導出我們班的所有學生的姓名,性別,出生日期,進校日期
正巧路飛剛看到Easypo,就打算用Easypoi來實現,實現方法如下:
首先定義一個我們導出的對象,為了節省篇幅,統一忽略getter,setter
public class StudentEntity implements java.io.Serializable { /** * id */ private String id; /** * 學生姓名 */ @Excel(name="學生姓名", height=20, width=30, isImportField="true_st") private String name; /** * 學生性別 */ @Excel(name="學生性別", replace={ "男_1", "女_2" }, suffix="生", isImportField="true_st") private int sex; @Excel(name="出生日期", databaseFormat="yyyyMMddHHmmss", format="yyyy-MM-dd", isImportField="true_st", width=20) private Date birthday; @Excel(name="進校日期", databaseFormat="yyyyMMddHHmmss", format="yyyy-MM-dd") private Date registrationDate; }
這里設置我們的4列分別是學生姓名,學生性別,出生日期,進校日期
其中學生姓名定義了我們的列的行高,學生性別因為我們基本上都是存在數據庫都是數字所以我們轉換下,兩個日期我們都是進行了格式化輸出了,這樣我們就完成了業務對我們Excel的樣式需求,后面只有把這個學生列表輸出就可以了
生成Excel代碼如下
Workbook workbook=ExcelExportUtil.exportExcel(new ExportParams("計算機一班學生","學生"), StudentEntity .class, list);
這樣我們就得到的一個java中的Excel,然后把這個輸出就得到我們的Excel了https://static.oschina.net/uploads/space/2017/0622/212811_uh7e_1157922.png
2.3.2 集合定義
路飛很快的完成了老師的任務,花了也就是喝杯茶的時間,就交差了,但過了一會就又被老師叫去了,讓他給出一個某個班級選擇選擇某些課的學生以及對應的老師
路飛又很快的想到了Easypoi,其中有一對多的導出,這不正是一對多的體現嗎,然后他繼續定義實體:
一個課程對應一個老師
一個課程對應N個學生
課程的實體
@ExcelTarget("courseEntity") public class CourseEntity implements java.io.Serializable { /** 主鍵 */ private String id; /** 課程名稱 */ @Excel(name="課程名稱", orderNum="1", width=25) private String name; /** 老師主鍵 */ @ExcelEntity(id="absent") private TeacherEntity mathTeacher; @ExcelCollection(name="學生", orderNum="4") private List<StudentEntity> students; }
教師的實體
@ExcelTarget("teacherEntity") public class TeacherEntity implements java.io.Serializable { private String id; /** name */ @Excel(name="主講老師_major,代課老師_absent", orderNum="1", isImportField="true_major,true_absent") private String name;
這里在課程這個實體里面就完成了一堆多的導出,達到了我們基礎需求,同時使用了orderNum對我們的列進行了排序,滿足老師的需求,導出代碼如下
Workbook workbook=ExcelExportUtil.exportExcel(new ExportParams("2412312", "測試", "測試"), CourseEntity.class, list);
這樣我們就完成了老師的需求,效果如圖2.3.2-1
但是課程名和代課老師沒有合并,不太美觀
路飛又果斷給課程名稱和代課老師加了needMerge=true的屬性,就可以完成單元格的合并
/** 課程名稱 */ @Excel(name="課程名稱", orderNum="1", width=25,needMerge=true) private String name; //-------------------------------- /** name */ @Excel(name="主講老師_major,代課老師_absent", orderNum="1",needMerge=true, isImportField="true_major,true_absent")
效果如圖2.3.2-2
到這里,路飛就完美的完成了老師的任務,快樂的去交差了
圖2.3.2-1
圖2.3.2-2
2.3.3 圖片的導出
在日常運作中不可避免的會遇到圖片的導入導出,這里提供了兩種類型的圖片導出方式
@Excel(name="公司LOGO", type=2 ,width=40 , height=20,imageType=1) private String companyLogo;
@Excel(name="公司LOGO", type=2 ,width=40 , height=20,imageType=1) private byte[] companyLogo;
效果如下
List<CompanyHasImgModel> list; @Before public void initData() { list=new ArrayList<CompanyHasImgModel>(); list.add(new CompanyHasImgModel("百度", "imgs/company/baidu.png", "北京市海淀區西北旺東路10號院百度科技園1號樓")); list.add(new CompanyHasImgModel("阿里巴巴", "imgs/company/ali.png", "北京市海淀區西北旺東路10號院百度科技園1號樓")); list.add(new CompanyHasImgModel("Lemur", "imgs/company/lemur.png", "亞馬遜熱帶雨林")); list.add(new CompanyHasImgModel("一眾", "imgs/company/one.png", "山東濟寧俺家")); } @Test public void exportCompanyImg() throws Exception { File savefile=new File("D:/excel/"); if (!savefile.exists()) { savefile.mkdirs(); } Workbook workbook=ExcelExportUtil.exportExcel(new ExportParams(), CompanyHasImgModel.class, list); FileOutputStream fos=new FileOutputStream("D:/excel/ExcelExportHasImgTest.exportCompanyImg.xls"); workbook.write(fos); fos.close(); }
運行效果
2.3.3 -1
2.3.4 Excel導入介紹
有導出就有導入,基于注解的導入導出,配置配置上是一樣的,只是方式反過來而已,比如類型的替換 導出的時候是1替換成男,2替換成女,導入的時候則反過來,男變成1 ,女變成2,時間也是類似
導出的時候date被格式化成 2017-8-25 ,導入的時候2017-8-25被格式成date類型
下面說下導入的基本代碼,注解啥的都是上面講過了,這里就不累贅了
@Test public void test2() { ImportParams params=new ImportParams(); params.setTitleRows(1); params.setHeadRows(1); long start=new Date().getTime(); List<MsgClient> list=ExcelImportUtil.importExcel( new File(PoiPublicUtil.getWebRootPath("import/ExcelExportMsgClient.xlsx")), MsgClient.class, params); System.out.println(new Date().getTime() - start); System.out.println(list.size()); System.out.println(ReflectionToStringBuilder.toString(list.get(0))); }
基本是寫法也很簡單,ImportParams 參數介紹下
屬性類型默認值功能titleRows
int
0
表格標題行數,默認0
headRows
int
1
表頭行數,默認1
startRows
int
0
字段真正值和列標題之間的距離 默認0
keyIndex
int
0
主鍵設置,如何這個cell沒有值,就跳過 或者認為這個是list的下面的值
這一列必須有值,不然認為這列為無效數據
startSheetIndex
int
0
開始讀取的sheet位置,默認為0
sheetNum
int
1
上傳表格需要讀取的sheet 數量,默認為1
needSave
boolean
false
是否需要保存上傳的Excel
needVerfiy
boolean
false
是否需要校驗上傳的Excel
saveUrl
String
"upload/excelUpload"
保存上傳的Excel目錄,默認是 如 TestEntity這個類保存路徑就是
upload/excelUpload/Test/yyyyMMddHHmss* 保存名稱上傳時間五位隨機數
verifyHanlder
IExcelVerifyHandler
null
校驗處理接口,自定義校驗
lastOfInvalidRow
int
0
最后的無效行數,不讀的行數
readRows
int
0
手動控制讀取的行數
importFields
String[]
null
導入時校驗數據模板,是不是正確的Excel
keyMark
String
":"
Key-Value 讀取標記,以這個為Key,后面一個Cell 為Value,多個改為ArrayList
readSingleCell
boolean
false
按照Key-Value 規則讀取全局掃描Excel,但是跳過List讀取范圍提升性能
僅僅支持titleRows + headRows + startRows 以及 lastOfInvalidRow
dataHanlder
IExcelDataHandler
null
數據處理接口,以此為主,replace,format都在這后面
2.3.5 Excel導入小功能
2.3.6 圖片的導入
有圖片的導出就有圖片的導入,導入的配置和導出是一樣的,但是需要設置保存路徑
1.設置保存路徑saveUrl 默認為"upload/excelUpload"
可以手動修改 ImportParams 修改下就可以了
@Test public void test() { try { ImportParams params=new ImportParams(); params.setNeedSave(true); List<CompanyHasImgModel> result=ExcelImportUtil.importExcel( new File(PoiPublicUtil.getWebRootPath("import/imgexcel.xls")), CompanyHasImgModel.class, params); for (int i=0; i < result.size(); i++) { System.out.println(ReflectionToStringBuilder.toString(result.get(i))); } Assert.assertTrue(result.size()==4); } catch (Exception e) { e.printStackTrace(); } } }
導入日志
16:35:43.081 [main] DEBUG c.a.e.e.imports.ExcelImportServer - Excel import start ,class is class cn.afterturn.easypoi.test.entity.img.CompanyHasImgModel 16:35:43.323 [main] DEBUG c.a.e.e.imports.ExcelImportServer - start to read excel by is ,startTime is 1503650143323 16:35:43.344 [main] DEBUG c.a.e.e.imports.ExcelImportServer - end to read excel by is ,endTime is 1503650143344 16:35:43.429 [main] DEBUG c.a.e.e.imports.ExcelImportServer - end to read excel list by pos ,endTime is 1503650143429 cn.afterturn.easypoi.test.entity.img.CompanyHasImgModel@1b083826[companyName=百度,companyLogo=upload/CompanyHasImgModel/pic88273295062.PNG,companyAddr=北京市海淀區西北旺東路10號院百度科技園1號樓] cn.afterturn.easypoi.test.entity.img.CompanyHasImgModel@105fece7[companyName=阿里巴巴,companyLogo=upload/CompanyHasImgModel/pic22507938183.PNG,companyAddr=北京市海淀區西北旺東路10號院百度科技園1號樓] cn.afterturn.easypoi.test.entity.img.CompanyHasImgModel@3ec300f1[companyName=Lemur,companyLogo=upload/CompanyHasImgModel/pic86390457892.PNG,companyAddr=亞馬遜熱帶雨林] cn.afterturn.easypoi.test.entity.img.CompanyHasImgModel@482cd91f[companyName=一眾,companyLogo=upload/CompanyHasImgModel/pic69566571093.PNG,companyAddr=山東濟寧俺家]
2.3.5-1
2.3.7 Excel多Sheet導出
目前單Sheet和單Class的方式比較多,對于多Sheet的方式還是一片空白,這里做一下說明:
導出基本采用ExportParams 這個對象,進行參數配置;
我們需要進行多Sheet導出,那么就需要定義一個基礎配置對象
public class ExportView { public ExportView(){ } private ExportParams exportParams; private List<?> dataList; private Class<?> cls; public ExportParams getExportParams() { return exportParams; } public void setExportParams(ExportParams exportParams) { this.exportParams=exportParams; } public Class<?> getCls() { return cls; } public void setCls(Class<?> cls) { this.cls=cls; } public List<?> getDataList() { return dataList; } public void setDataList(List<?> dataList) { this.dataList=dataList; } public ExportView(Builder builder) { this.exportParams=builder.exportParams; this.dataList=builder.dataList; this.cls=builder.cls; } public static class Builder { private ExportParams exportParams=null; private List<?> dataList=null; private Class<?> cls=null; public Builder() { } public Builder exportParams(ExportParams exportParams) { this.exportParams=exportParams; return this; } public Builder dataList(List<?> dataList) { this.dataList=dataList; return this; } public Builder cls(Class<?> cls) { this.cls=cls; return this; } public ExportView create() { return new ExportView(this); } } }
對象主要有三個屬性:
// 該注解配置的導出屬性
這里沒有用泛型,因為多Sheet導出時,會引用到不同的注解對象;
定義基礎配置的集合
public class ExportMoreView { private List<ExportView> moreViewList=Lists.newArrayList(); public List<ExportView> getMoreViewList() { return moreViewList; } public void setMoreViewList(List<ExportView> moreViewList) { this.moreViewList=moreViewList; } }
最后在實現調用的方法中,對整個集合進行配置和解析
List<Map<String, Object>> exportParamList=Lists.newArrayList(); //該行主要用于獲取業務數據,請根據具體的情況進行修改和調整 ExportMoreView moreView=this.getBaseTransferService().mergeExportView(templateTypeCode); //迭代導出對象,將對應的配置信息寫入到實際的配置中 for(ExportView view:moreView.getMoreViewList()){ Map<String, Object> valueMap=Maps.newHashMap(); valueMap.put(NormalExcelConstants.PARAMS,view.getExportParams()); valueMap.put(NormalExcelConstants.DATA_LIST,view.getDataList()); valueMap.put(NormalExcelConstants.CLASS,view.getCls()); exportParamList.add(valueMap); } //實現導出配置 modelMap.put(NormalExcelConstants.FILE_NAME,new DateTime().toString("yyyyMMddHHmmss")); //將轉換完成的配置接入到導出中 modelMap.put(NormalExcelConstants.MAP_LIST,exportParamList); return NormalExcelConstants.JEECG_EXCEL_VIEW;
如果不是采用的MVC的方式,請將轉換的配置采用以下的方式實現:
參見ExcelExportUtil
2.4 注解變種-更自由的導出
這天老師又把路飛喊道的辦公室,要求路飛導出班級學生的整體信息
@Excel(name="學生姓名", height=20, width=30, isImportField="true_st") private String name; @Excel(name="學生性別", replace={ "男_1", "女_2" }, suffix="生", isImportField="true_st") private int sex; @Excel(name="出生日期", databaseFormat="yyyyMMddHHmmss", format="yyyy-MM-dd", isImportField="true_st", width=20) private Date birthday; @Excel(name="進校日期", databaseFormat="yyyyMMddHHmmss", format="yyyy-MM-dd") private Date registrationDate;
路飛飛快的用到上面的學到的知識搞定了,這這時有一個老師把路飛叫去,說想要導出一個不要出生日期的Excel,感覺用戶需求很無奈,路飛又造兩個一個bean,把這個注解去掉了,來導出
@Excel(name="學生姓名", height=20, width=30, isImportField="true_st") private String name; @Excel(name="學生性別", replace={ "男_1", "女_2" }, suffix="生", isImportField="true_st") private int sex; @Excel(name="進校日期", databaseFormat="yyyyMMddHHmmss", format="yyyy-MM-dd") private Date registrationDate;
雖然解決了老師的需求,但這個并不是一個完美的解決方案,下面介紹一個更自由的解決方案
注解的導出,規定我們必須把model寫好,并且注解寫好,每次導出的Excel都是固定的,無法動態控制導出的列,雖然可以通過id來處理一個案例,但是自由度遠遠不夠,這里介紹個變種支持,基本支持注解所有的功能
基于List<ExcelExportEntity> 的導出,ExcelExportEntity是注解經過處理翻譯成的實體類,兩者幾乎是一對的,所以如果我們要動態自定義導出列,我們只要動態拼裝ExcelExportEntity就可以了
下面我們看下這個類
/** * 如果是MAP導出,這個是map的key */ private Object key; private double width=10; private double height=10; /** * 圖片的類型,1是文件,2是數據庫 */ private int exportImageType=0; /** * 排序順序 */ private int orderNum=0; /** * 是否支持換行 */ private boolean isWrap; /** * 是否需要合并 */ private boolean needMerge; /** * 單元格縱向合并 */ private boolean mergeVertical; /** * 合并依賴 */ private int[] mergeRely; /** * 后綴 */ private String suffix; /** * 統計 */ private boolean isStatistics; private String numFormat; private List<ExcelExportEntity> list;
基本上是和注解對應的, List<ExcelExportEntity> list 這個是對應的一對多的導出,相當于集合,其他基本上都是和注解保持一致
下面給出正常的demo
public void test() { try { List<ExcelExportEntity> entity=new ArrayList<ExcelExportEntity>(); //構造對象等同于@Excel ExcelExportEntity excelentity=new ExcelExportEntity("姓名", "name"); excelentity.setNeedMerge(true); entity.add(excelentity); entity.add(new ExcelExportEntity("性別", "sex")); excelentity=new ExcelExportEntity(null, "students"); List<ExcelExportEntity> temp=new ArrayList<ExcelExportEntity>(); temp.add(new ExcelExportEntity("姓名", "name")); temp.add(new ExcelExportEntity("性別", "sex")); //構造List等同于@ExcelCollection excelentity.setList(temp); entity.add(excelentity); List<Map<String, Object>> list=new ArrayList<Map<String, Object>>(); //把我們構造好的bean對象放到params就可以了 Workbook workbook=ExcelExportUtil.exportExcel(new ExportParams("測試", "測試"), entity, list); FileOutputStream fos=new FileOutputStream("D:/excel/ExcelExportForMap.tt.xls"); workbook.write(fos); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
路飛想到了這個方案,并且用上面做了測試可以完美解決所以他把之前的代碼改為了(代碼有刪減,基本上都是和注解對應的)
List<ExcelExportEntity> beanList=new ArrayList<ExcelExportEntity>(); beanList .add(new ExcelExportEntity(new ExcelExportEntity("學生姓名", "name")); beanList .add(new ExcelExportEntity("學生性別", "sex")); beanList .add(new ExcelExportEntity("進校日期", "registrationDate")); if(needBirthday()){ beanList .add(new ExcelExportEntity("出生日期", "birthday")); } Workbook workbook=ExcelExportUtil.exportExcel(new ExportParams("測試", "測試"), beanList , list);
用同一套代買完美了支持了老師的需求,心滿意足的回宿舍了^^
2.5 Map導入,自由發揮
這天,老師把路飛叫到辦公室,總是被叫,能者的悲哀啊,讓他臨時導入一批數據,到數據庫,但是中間需要處理一些字段邏輯沒辦法直接導入到數據庫,
這時路飛首先想到構造一個bean然后標記注解,導入處理對象,但是想想一次的對象太過于浪費,不如用map試試,獲取map處理map也是一樣的
導入的邏輯就變成了
ImportParams params=new ImportParams(); params.setDataHanlder(new MapImportHanlder()); long start=new Date().getTime(); List<Map<String, Object>> list=ExcelImportUtil.importExcel( new File(PoiPublicUtil.getWebRootPath("import/check.xls")), Map.class, params);
導入后,處理每個map,然后入庫完美的解決了老師的需求,簡單更快捷,和bean導入基礎沒有區別,省去了bean的構造時間
PS:這個作者也只是在臨時方案中或者一次性活當中使用,一般還是推薦注解這種方式,擁有更高的代碼閱讀性
!!!測試了時間的,最好導入使用文本格式,可以獲取時間格式可能無法獲取
2.6 Excel的樣式自定義
"路飛,來辦公室一趟",就這樣路飛又被叫到了辦公室,這次老師的需求是,想要一個漂亮點的Excel,希望路飛可以點綴下Excel,思來想去還是需要用poi的style來解決,但是如果每個都寫style是不是太麻煩,而且Excel的styler數量是有限制的,這里就需要盡量復用已經創造的style,看看之前的Excel表格,大體上可以分為[標題,表頭,表體],那可以說的就是創建一個接口每次調用這三個接口就可以了不說干就干
public interface IExcelExportStyler { /** * 列表頭樣式 * @param headerColor * @return */ public CellStyle getHeaderStyle(short headerColor); /** * 標題樣式 * @param color * @return */ public CellStyle getTitleStyle(short color); /** * 獲取樣式方法 * @param Parity * @param entity * @return */ public CellStyle getStyles(boolean Parity, ExcelExportEntity entity); }
實現類盡量復用已經創建的Styler,切記
這樣路飛先造了一個帶邊框的styler ,ExcelExportStylerBorderImpl
效果如下
然后路飛又手癢寫了個帶換行顏色的 ExcelExportStylerColorImpl
效果如下
客官看到這里應該就大體理解了我們的實現方法了吧,
最后路飛實現了一個復雜的按照老師要求的樣式交差了
styler接口用法
上面兩個表頭和標題樣式不用解釋
后面這個是傳入當前列的以及奇偶行,用戶可以根據需求實現業務,包括去掉Excel的小箭頭(也就是設置數字為數字格式的Cell),完成居中,字體等等各式各樣的需求
但是這里無法實現特別沒的Excel,如果有這種需求可以使用模板來實現,在Excel點點就可以完美實現
獲取源碼方式 轉發+【關注】,私信回復【eypoi】,即可免費獲取源碼地址
家好,接下來幾篇文章我將分享基于SSM整合POI實現Excel的導入導出,并介紹如何采用MVC三層模式體驗企業級JavaWeb應用的開發流程。而這些功能我進行了整理并錄制了一套完整的視頻教程,具體的功能列表如下:
1、SSM的整合流程;
2、POI導入導出Excel;
3、增加、刪除、修改、搜索功能。
其中,我對整個項目進行了兩種方式的整合:第一種是采用傳統的往lib目錄丟jar包;第二種是采用maven的方式進行整合;而視頻教程中采用的是第一種方式。當然啦,這兩種方式的源碼我這里都有!感興趣的童鞋可以私聊!
大家也可以搜索“程序員實戰基地”,關于poi實現Excel導入導出介紹視頻鏈接如下:
http://list.youku.com/albumlist/show/id_51818026.html
在開發前端這塊大多使用 SpringMVC,EasyPOI 也提供了 對 SpringMVC 的支持;
EasypoiBigExcelExportView 大數據量導出
EasypoiMapExcelView map 列表導出
EasypoiPDFTemplateView pdf導出
EasypoiSingleExcelView 注解導出
EasypoiTemplateExcelView 模板導出
EasypoiTemplateWordView word模板導出
MapGraphExcelView 圖表導出
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<%@include file="/WEB-INF/views/head.jsp" %>
</head>
<body>
<span style="color: red">${count}</span>
<!-- 上傳請配置enctype -->
<form action="/import/xlsx" method="post" enctype="multipart/form-data">
<input class="easyui-filebox" name="xlsxFile" data-options="prompt:'選擇一個文件...'" style="width:80%">
<button class="easyui-linkbutton" type="submit">確定</button>
</form>
</body>
</html>
@Controller
@RequestMapping("/import")
public class ImportController extends BaseController {
@Autowired
private IEmployeeService employeeService;
@Autowired
private IDepartmentService departmentService;
//跳轉到導入頁面
@RequestMapping("/index")
public String index(){
return "import";
}
//跳轉到導入頁面
@RequestMapping("/xlsx")
public String importXlsx(MultipartFile xlsxFile, HttpServletRequest request, HttpServletResponse response) throws Exception{
ImportParams params=new ImportParams();
params.setTitleRows(1); //注意:這里有兩個表頭
List<Employee> list=ExcelImportUtil.importExcel(
xlsxFile.getInputStream(),
Employee.class, params);
for (Employee employee : list) {
employee.setPassword("123"); //默認密碼123
if(employee.getDepartment()!=null) {
Department department=departmentService.findByName(employee.getDepartment().getName());
employee.setDepartment(department);
}
employeeService.save(employee);
}
return "import";
}
}
自定義驗證需要實現IExcelVerifyHandler接口
*請認真填寫需求信息,我們會在24小時內與您取得聯系。