整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          程序員接私活利器 玩轉excel導入導出

          程序員接私活利器 玩轉excel導入導出

          什么會寫Easypoi

          以前的以前(歲月真TMD的快)我雖然寫了不少代碼但還是很少寫poi,然后跳到一家公司之后就和業務人員聊上了,來這個需要個報表,這個報表樣式是這樣的,這個表頭是這樣的,就這樣我寫了大量的poi代碼,每次都是大量的篇幅,copy to copy,無聊的一逼,然后加入了jeecg,jeecg中有一個小的工具類,雖然我也不知道是誰寫的,然是可以用注解搞定最簡單的導出,突然豁然開朗,我可以完善,讓我從報表的苦海當中脫離出來,這樣我花了一周的時間做了第一個版本支持導入導出放到了jeecg,發現還是不錯的,慢慢的用的人越來越多,我就把這塊獨立出來了,再然后有人提出了模板,然后就加入了模板功能,提出了word的需求,加入了word的功能,后來工作忙了雖然沒再參與jeecg,但還是一直維持這easypoi的更新,根據見識的增長也不斷的重構這代碼,直到現在

          獨特的功能

          • 基于注解的導入導出,修改注解就可以修改Excel
          • 支持常用的樣式自定義
          • 基于map可以靈活定義的表頭字段
          • 支持一堆多的導出,導入
          • 支持模板的導出,一些常見的標簽,自定義標簽
          • 支持HTML/Excel轉換,如果模板還不能滿足用戶的變態需求,請用這個功能
          • 支持word的導出,支持圖片,Excel

          小白如何開始

          • 下載demo運行看看,基本上常見的用用法都在里面easypoi-test
          • 查看幾個*Util的用法,Easypoi的主要輸出就是這個
          • 看看注解的意思
          • 看看模板的標簽用法
          • 可以出師了

          Easypoi 為誰而開發

          • 不太熟悉poi的
          • 不想寫太多重復太多的
          • 只是簡單的導入導出的
          • 喜歡使用模板的

          都可以使用easypoi

          Easypoi的目標是什么

          Easypoi的目標不是替代poi,而是讓一個不懂導入導出的快速使用poi完成Excel和word的各種操作,而不是看很多api才可以完成這樣工作

          1.3 使用

          • 1.easypoi 父包--作用大家都懂得
          • 2.easypoi-annotation 基礎注解包,作用與實體對象上,拆分后方便maven多工程的依賴管理
          • 3.easypoi-base 導入導出的工具包,可以完成Excel導出,導入,Word的導出,Excel的導出功能
          • 4.easypoi-web 耦合了spring-mvc 基于AbstractView,極大的簡化spring-mvc下的導出功能
          • 5.sax 導入使用xercesImpl這個包(這個包可能造成奇怪的問題哈),word導出使用poi-scratchpad,都作為可選包了

          如果不使用spring mvc的便捷福利,直接引入easypoi-base 就可以了,easypoi-annotation

          1.4 測試項目

          測試這個事情真不是個容易的事情

          測試項目包括兩塊 Junit 的常見測試和spring 的view測試

          1.spring view測試

          運行application就可以了,訪問界面,然后看到界面

          對應的代碼在view下面

          2.Junit的測試目錄結構如下

          • tohtml html預覽測試
          • view 導出的view測試
          • cache 自定義緩存測試
          • html html互轉測試
          • test
          • excel
          • read 讀取Excel測試
          • check 導入檢查測試
          • hanlder 導入數據處理
          • img 含圖片導入測試
          • styler 導出樣式自定義測試
          • template 模板導出測試
          • sum 導出含統計測試
          • test 導出測試
          • groupname groupname 屬性測試
          • img 導出圖片測試
          • pdf pdf測試
          • word word導出測試
          • util util 內部測試

          目前的測試覆蓋率

          2. Excel 注解版

          2.1 Excel導入導出

          Excel的導入導出是Easypoi的核心功能,前期基本也是圍繞這個打造的,主要分為三種方式的處理,其中模板和Html目前只支持導出,因為支持Map.class其實導入應該是怎樣都支持的

          • 注解方式,注解變種方式
          • 模板方式
          • Html方式

          下面分別就這三種方式進行講解

          2.2 注解

          注解介紹

          easypoi起因就是Excel的導入導出,最初的模板是實體和Excel的對應,model--row,filed--col 這樣利用注解我們可以和容易做到excel到導入導出

          經過一段時間發展,現在注解有5個類分別是

          • @Excel 作用到filed上面,是對Excel一列的一個描述
          • @ExcelCollection 表示一個集合,主要針對一對多的導出,比如一個老師對應多個科目,科目就可以用集合表示
          • @ExcelEntity 表示一個繼續深入導出的實體,但他沒有太多的實際意義,只是告訴系統這個對象里面同樣有導出的字段
          • @ExcelIgnore 和名字一樣表示這個字段被忽略跳過這個導導出
          • @ExcelTarget 這個是作用于最外層的對象,描述這個對象的id,以便支持一個對象可以針對不同導出做出不同處理

          注解中的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;
          
          1. 表示type=2 該字段類型為圖片,imageType=1 (默認可以不填),表示從file讀取,字段類型是個字符串類型 可以用相對路徑也可以用絕對路徑,絕對路徑優先依次獲取
          @Excel(name="公司LOGO", type=2 ,width=40 , height=20,imageType=1)
           private byte[] companyLogo;
          
          1. 2.表示type=2 該字段類型為圖片,imageType=2 ,表示從數據庫或者已經讀取完畢,字段類型是個字節數組 直接使用 同時,image 類型的cell最好設置好寬和高,會百分百縮放到cell那么大,不是原尺寸,這里注意下

          效果如下

          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導入小功能

          1. 讀取指定的sheet
          2. 比如要讀取上傳得第二個sheet 那么需要把startSheetIndex=1 就可以了
          3. 讀取幾個sheet
          4. 比如讀取前2個sheet,那么 sheetNum=2 就可以了
          5. 讀取第二個到第五個sheet
          6. 設置 startSheetIndex=1 然后sheetNum=4
          7. 讀取全部的sheet
          8. sheetNum 設置大點就可以了
          9. 保存Excel
          10. 設置 needVerfiy=true,默認保存的路徑為upload/excelUpload/Test/yyyyMMddHHmss* 保存名稱上傳時間五位隨機數
          11. 如果自定義路徑 修改下saveUrl 就可以了,同時saveUrl也是圖片上傳時候的保存的路徑
          12. 判斷一個Excel是不是合法的Excel
          13. importFields 設置下值,就是表示表頭必須至少包含的字段,如果缺一個就是不合法的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);
           }
           }
          }
          

          對象主要有三個屬性:

          // 該注解配置的導出屬性

          1. ExportParams exportParams // 對應注解 class 實例對象的數據集合
          2. List<?> dataList // 對應注解的 class
          3. Class<?> cls

          這里沒有用泛型,因為多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

          asyPOI 與 SpringMVC

          在開發前端這塊大多使用 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

          @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接口


          主站蜘蛛池模板: 国产一区二区精品久久岳√| 鲁丝丝国产一区二区| 中文字幕无码不卡一区二区三区| 国产免费私拍一区二区三区| 麻豆高清免费国产一区| 熟女性饥渴一区二区三区| 免费一区二区无码视频在线播放| 亚洲午夜电影一区二区三区| 久久一区二区三区免费播放| 国产天堂一区二区综合| 精品一区二区三区无码视频| 日本精品视频一区二区三区| 蜜桃AV抽搐高潮一区二区| 亚洲综合一区国产精品| 一区二区和激情视频| 国产成人亚洲综合一区| 亚洲AV成人精品日韩一区| 无码日韩人妻av一区免费| 无码少妇A片一区二区三区| 精品国产a∨无码一区二区三区 | 亚洲一区二区三区在线视频| 国产伦精品一区二区三区在线观看| 国产精品成人免费一区二区 | 日韩精品在线一区二区| 国产午夜精品一区理论片飘花| 国产精品一区12p| 中文字幕Av一区乱码| 国产一区二区电影| 久久久无码精品国产一区| 日日摸夜夜添一区| 国产精品综合一区二区三区| 精品女同一区二区三区免费播放| 午夜视频久久久久一区| 中文字幕在线观看一区| 亚洲一区二区电影| 国模大胆一区二区三区| 国产高清在线精品一区小说| 久久一区二区三区精品| 亚洲精品国产suv一区88| 精品一区二区三区AV天堂| 人妻少妇一区二区三区|