項目地址:http://git.oschina.net/lis1314/easy-exceljava
使用easy-excel 完成Excel導入導出功能git
下面有以下的幾個模型spring
學生模型,圖書模型,做者模型數據庫
//學生模型 public class StudentModel { /** ID */ protected String id; /** 建立時間 */ protected Date createTime; /** 姓名 */ private String name; /** 年齡 */ private Integer age; /** 學號 */ private String studentNo; /** 建立人 */ private String createUser; /** 建立人ID */ private String createUserId; /** 狀態 */ private Integer status; /** 圖書信息 */ private BookModel book; //略 getter setter... } //圖書模型 public class BookModel { /** 圖書名稱 */ private String bookName; /** 做者信息 */ private AuthorModel author; //略 getter setter... } //做者模型 public class AuthorModel { /** 做者姓名 */ private String authorName; //略 getter setter... }
有以下的Excel文件格式,須要映射成學生實體類app
那麼使用easy-excel 如何導入呢?jvm
前兩行是屬於不規則的數據,從標題行之後纔是規則的數據,也就是從規則數據以後才能正常轉換成JavaBean。maven
下面使用easy-excel進行導入測試
一、下載easy-excel,引入到本身的工程,它是一個jar的maven工程,直接添加依賴便可字體
http://git.oschina.net/lis1314/easy-excelui
二、具體實現代碼,首先編寫配置文件:excel-config.xml
<excels> <excel id="student" class="org.easy.excel.test.model.StudentModel"> <field name="id" title="ID"/> <field name="name" title="學生姓名"/> <field name="age" title="年齡" isNull="false" regex="^[1-9]\d*$" regexErrMsg="必須是數字"/> <field name="studentNo" title="學號" isNull="false" /> <field name="createTime" title="建立時間" pattern="yyyy-MM-dd,yyyy/MM/dd"/> <field name="status" title="狀態" format="1:正常,0:禁用,-1:無效" /> <field name="createUser" title="建立人"/> <!-- 複雜對象 --> <field name="book.bookName" title="圖書名稱" /> <field name="book.author.authorName" title="做者名稱"/> </excel> </excels>
解釋,每一個excel表示一種Excel文件到JavaBean的映射規則,該規則能夠是導入和導出
標籤解釋
配置了一個id爲student的映射,要映射對應的JavaBean實體爲 StudentModel
<excel id="student" class="org.easy.excel.test.model.StudentModel">
excel文件中標題爲ID的列,把它的值映射到 StudentModel .id屬性上
<field name="id" title="ID"/>
isNull屬性,表示在excel文件中標題爲【年齡】的單元格的值不能爲空,而且符合正則【 regex 】,當正則校驗沒有經過時,會提示【xxx行,[ 年齡 ]必須是數字,若是爲空同理,xxx行[年齡]不能爲空】
<field name="age" title="年齡" isNull="false" regex="^[1-9]\d*$" regexErrMsg="必須是數字"/>
pattern:不作過多解釋,SimpleDateFormat(pattern),導入數據時字符串的值如何轉換成日期
支持多種映射pattern,使用【英文逗號】進行分割
<field name="createTime" title="建立時間" pattern="yyyy-MM-dd,yyyy/MM/dd"/>
format屬性,觀察上面的excel文件結構會發現狀態列是中文,那麼導入時,可能javaBean中並非中文,而是數字或其餘,那麼如何把它轉換成數字呢?format就是作這個事情的。導入時它會以【,分割:前面的做爲導入時使用的值,:後面的做爲導出時使用的值】:後面值進行逆推,導出時同理。思考一個問題?若是這個值不肯定如何解決,或者這個值須要到數據庫校驗?好比是個城市地址,這個時候是須要查詢數據庫進行比對的,若是地址不存在則拋出錯誤提示信息的,就說這麼多,easy-excel已經作好了,支持自定義的轉換器能夠解決。
<field name="status" title="狀態" format="1:正常,0:禁用,-1:無效" />
把excel文件標題爲【圖書名稱】的值映射到 StudentModel 類中的book類中的bookName屬性上
<field name="book.bookName" title="圖書名稱" />
-----------不每條配置都解釋了,明白標籤的做用我想你們能看懂。下面展現Java代碼
public class ImportTest { public static void main(String[] args) throws Exception { //準備excel文件流 InputStream excelStream = new FileInputStream("C:/Users/Administrator/Desktop/stu.xlsx"); //建立excel上下文實例,它的構成須要配置文件的路徑 ExcelContext context = new ExcelContext("excel-config.xml"); //按照xml配置中id爲student的配置形式讀取excel文件,並轉換成StudentModel //這裏的第二個參數是值,標題是第幾行開始,以前也說了標題以前的數據並非規則的數據 ExcelImportResult result = context.readExcel("student", 2,excelStream); //打印導入結果,查看標題以前不規則的數據 List<List<Object>> header = result.getHeader(); System.out.println(header.get(0)); System.out.println(header.get(1)); //查看學生集合導入結果 List<StudentModel> students = result.getListBean(); for(StudentModel stu:students){ System.out.println(stu); } } }
運行結果:
[共導出【10】條數據] [本次批次號爲:XXX] StudentModel [id=1, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=張三0, age=20, studentNo=Stu_0, createUser=王五0, createUserId=null, status=1, book=BookModel [bookName=Thinking in java, author=AuthorModel [authorName=Bruce Eckel]]] StudentModel [id=2, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=張三1, age=21, studentNo=Stu_1, createUser=王五1, createUserId=null, status=0, book=null] StudentModel [id=3, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=張三2, age=22, studentNo=Stu_2, createUser=王五2, createUserId=null, status=1, book=BookModel [bookName=Thinking in java, author=AuthorModel [authorName=Bruce Eckel]]] StudentModel [id=4, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=張三3, age=23, studentNo=Stu_3, createUser=王五3, createUserId=null, status=0, book=null] StudentModel [id=5, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=張三4, age=24, studentNo=Stu_4, createUser=王五4, createUserId=null, status=1, book=BookModel [bookName=Thinking in java, author=AuthorModel [authorName=Bruce Eckel]]] StudentModel [id=6, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=張三5, age=25, studentNo=Stu_5, createUser=王五5, createUserId=null, status=0, book=null] StudentModel [id=7, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=張三6, age=26, studentNo=Stu_6, createUser=王五6, createUserId=null, status=1, book=BookModel [bookName=Thinking in java, author=AuthorModel [authorName=Bruce Eckel]]] StudentModel [id=8, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=張三7, age=27, studentNo=Stu_7, createUser=王五7, createUserId=null, status=0, book=null] StudentModel [id=9, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=張三8, age=28, studentNo=Stu_8, createUser=王五8, createUserId=null, status=1, book=BookModel [bookName=Thinking in java, author=AuthorModel [authorName=Bruce Eckel]]] StudentModel [id=10, createTime=Sat Jun 18 00:00:00 GMT+08:00 2016, name=張三9, age=29, studentNo=Stu_9, createUser=王五9, createUserId=null, status=0, book=null]
導入結束,完美導入,其實上面的代碼有些都不少餘,那麼核心的代碼是哪幾行?
//準備excel文件流 InputStream excelStream = new FileInputStream("C:/Users/Administrator/Desktop/stu.xlsx"); //建立excel上下文實例,它的構成須要配置文件的路徑 ExcelContext context = new ExcelContext("excel-config.xml"); //按照xml配置中id爲student的配置形式讀取excel文件,並轉換成StudentModel //這裏的第二個參數是值,標題是第幾行開始,以前也說了標題以前的數據並非規則的數據 ExcelImportResult result = context.readExcel("student", 2,excelStream);
只有準備數據、建立上下文、讀取excel。。一般在真實的常見建立上下文均可以省略了,由於它會交給spring容器管理,整個jvm中,只保持一個實例就夠了。
關於導入配置的一個很重要的屬性:cellValueConverter
在上面並無配置它,這個屬性就是能夠解決以前我標記爲紅色的問題。那麼它是什麼?
它是一個CellValueConverter接口的實現類:假設咱們的Excel中有地址,或者結合業務中多是其餘,都是須要查詢數據庫,或者通過更復雜的業務邏輯進行校驗的,那麼咱們能夠配置它。咱們來觀察這個接口作了什麼事?
/** * CellValue轉換器,用於解析cell值的規則 * @author lisuo * */ public interface CellValueConverter { /** * 操做類型,導入或導出 */ enum Type { EXPORT, IMPORT } /** * 轉換cell的值 * @param bean Excel配置的JavaBean對象 * @param value Excel原值 * @param fieldValue FieldValue信息 * @param type 導入或導出 * @param rowNum 行號 * @return 解析結果對應的value * @throws Exception */ public Object convert(Object bean,Object value, FieldValue fieldValue, Type type,int rowNum) throws Exception; }
核心只有一個方法convert
咱們能夠自定義它的實現類,而後把全類名註冊到 cellValueConverter屬性上
如:假設建立人是須要查詢用戶表進行校驗,若是沒有則不容許導入,咱們則能夠在自定義的實現類拋出一個異常, 能夠精準的提示用戶多少行,哪個字段【標題】的值錯誤了。
這裏不在展現代碼了,具體查看http://git.oschina.net/lis1314/easy-excel中的源代碼
<field name="createUser" title="建立人" cellValueConverter="org.easy.excel.test.converter.CreateUserCellValueConverter"/>
如何使用easy-excel 進行導出?
以前的配置信息徹底不變,直接上java代碼
public class ExportTest { public static void main(String[] args) throws Exception { //準備excel輸出流 OutputStream ops = new FileOutputStream("C:/Users/Administrator/Desktop/exportStudent.xlsx"); //建立excel上下文實例,它的構成須要配置文件的路徑 ExcelContext context = new ExcelContext("excel-config.xml"); //獲取POI建立結果 Workbook workbook = context.createExcel("student",getStudents()); workbook.write(ops); ops.close(); workbook.close(); } //獲取模擬數據,數據庫數據... public static List<StudentModel> getStudents(){ int size = 10; List<StudentModel> students = new ArrayList<>(size); for(int i=0;i<size;i++){ StudentModel stu = new StudentModel(); stu.setId(""+(i+1)); stu.setName("張三"+i); stu.setAge(20+i); stu.setStudentNo("Stu_"+i); stu.setCreateTime(new Date()); stu.setStatus(i%2==0?1:0); stu.setCreateUser("王五"+i); //建立複雜對象 if(i % 2==0){ BookModel book = new BookModel(); book.setBookName("Thinking in java"); AuthorModel author = new AuthorModel(); author.setAuthorName("Bruce Eckel"); book.setAuthor(author); stu.setBook(book); } students.add(stu); } return students; } }
運行結果生成文件:
其餘更多導出示例參看http://http://git.oschina.net/lis1314/easy-excel中的源代碼
導出的一些疑問?支持樣式麼?支持在標題以前建立點其餘的信息麼?
目前支持cell寬度設置,sheet名稱自定義,標題背景顏色,標題字體顏色,標題對齊方式,單元格樣式是否與標題統同樣式,默認cell對齊方式
對應相關標籤
columnWidth,sheetname,titleBgColor,titleFountColor,align,enableStyle,defaultAlign。
支持導出前自定義頭信息。
--上面紅色標籤部分爲最新加入標籤
補充:如何在本身工程中與spring無縫集成以及使用?
在你的spring.xml配置文件中加入
<!-- Excel上下文 --> <bean id="excelContext" class="org.easy.excel.ExcelContext"> <constructor-arg> <!--你本身的excel配置文件路徑,支持classpath前綴,若是不寫前綴,默認爲classpath:--> <value>excel-config.xml</value> </constructor-arg> </bean> <!-- 初始化SpringUtil --> <bean id="springUtil" class="org.easy.util.SpringUtil"/>
關於海量數據導出問題,看以下代碼,很是easy
/*** * 導出測試,分屢次導出 * @throws Exception */ @Test public void testExporPart()throws Exception{ //需求概述.數據量較大,可能大批量數據導出,會對DB形成壓力,這裏分批次檢索數據,一部分一部分向Excel中寫 OutputStream ops = new FileOutputStream(path); ExcelExportResult exportResult = context.createExcelForPart(excelId,getStudents()); //假設這是第二次從數據庫或其餘平臺查詢到到數據 exportResult.append(getStudents()); //第n次.... exportResult.append(getStudents()); exportResult.append(getStudents()); exportResult.append(getStudents()); exportResult.append(getStudents()); Workbook workbook = exportResult.build(); workbook.write(ops); ops.close(); workbook.close(); }
2016-09-02加入一下4個標籤:
otherConfig:以下面XML註釋,我遇到額需求是處理字典,只有Key不一樣,其餘邏輯如出一轍。那麼我經過otherConfig達到動態傳參的功能。
<!-- 當一個轉換器處理多個字段時,可能邏輯同樣,只有個別的參數不同,那麼可使用otherConfig,動態傳遞 --> <field name="createUser" title="建立人" cellValueConverter="org.easy.excel.test.converter.CreateUserFieldValueConverter" otherConfig="Test動態傳遞的一個變量"/>
defaultValue:不管是導入仍是導出都給一個默認值
<!-- defaultValue,不管是導入仍是導出當值爲空給一個默認值 --> <field name="book.price" title="圖書價格" columnWidth="6000" defaultValue="0.00"/>
decimalFormatPattern:Number格式處理
<!-- 對Number類型進行處理,好比(12345.12),轉換成(123,45.12),導入的規則是從字符到Number,導出是從Number到字符,基於標準的java.text.DecimalFormat --> <field name="book.price" title="圖書價格" columnWidth="6000" decimalFormatPattern="###,##0.00" defaultValue="0.00"/>
roundingMode:結合上麼的decimalFormatPattern標籤,對於小數位數處理方案進行配置,默認向下取整
<!-- 當處理字符時,假設保留2位小數,那麼遇到3位甚至更多的位數如何處理?經過該配置能夠指定處理方式,默認向下取整 --> <field name="book.price" title="圖書價格" columnWidth="6000" decimalFormatPattern="###,##0.00" roundingMode="up" defaultValue="0.00"/>
2017-03-21 變動:
主要對工程進行了重構,對一些包從新進行了劃分以及命名
重命名resolveFieldValueConverterName配置爲cellValueConverter
在ExcelDefinition中增長了
sheetIndex屬性,支持指定sheet形式讀取內容
增長了
ExcelUtil ,用於讀取沒有規則的Excel文件
ExcelDownLoadUtil,用於WEB環境Excel文件的下載
SpringMvcExcelView,用於WEB環境使用SpringMvc輕鬆實現下載
與SpringMvc整合
正常整合,把org.easy.util.view.SpringMvcExcelView添加到SpringMvc容器中,使用標準的Spring自定義視圖跳轉便可,參看org.easy.util.view.SpringMvcExcelView這個類的註釋部分
2017-03-30 變動:支持多行導入校驗
例子代碼
//具體參看 ImportMultiValidateTest 測試類 ExcelImportResult result = context.readExcel(excelId, titleIndex, excelStream,true); //經過導入結果集的hasErrors方法判斷 if(result.hasErrors()){ System.out.println("導入包含錯誤,下面是錯誤信息:"); for (ExcelError err:result.getErrors()) { System.out.println(err.getErrorMsg()); } } //運行結果 導入包含錯誤,下面是錯誤信息: 第[1行],[建立時間][D]不能轉換成日期,正確的格式應該是:[yyyy-MM-dd] 第[1行],[狀態][不正常]取值錯誤 第[2行],[做者名稱]不能爲空 第[4行],[做者名稱]不能爲空
更多信息請參考源代碼工程中的org.easy.excel.test包下的幾個類