EasyExcel使用筆記


官方Github地址:https://github.com/alibaba/easyexcel

官方使用說明:https://alibaba-easyexcel.github.io/index.html

使用步驟:

  1. 在頁面上新增導入按鈕和文件選擇框,代碼參考:
    <a id="btnImport" class="easyui-linkbutton" data-options="iconCls:'icon-save'" onclick="selectFile()" style="float: right;">導入</a>
    <input id="filebox" name="filebox" type="file" onchange="uploadFile()" style="float:right;display:none;" />
  2. 加入JavaScript方法調用后台,代碼參考:
     1     function selectFile(){
     2         $("#filebox").click();
     3     }
     4     function uploadFile() {
     5         if(isLowerIE10()){
     6             $.messager.alert('錯誤', "當前瀏覽器版本太低,請使用IE10及以上或者其他瀏覽器",'error');
     7         } else {
     8             var file = $("#filebox").val();    
     9              if (file.endWith(".xlsx")) {
    10                 var options = {
    11                     type : 'post',
    12                     url : "upload.do",
    13                     dataType : 'json',
    14                     complete : function(result) {
    15                         $('#dg').datagrid("loaded");
    16                         var result = result.responseJSON;
    17                         $.messager.alert('操作提示', result.msg,'info',function(){
    18                             $('#dg').datagrid('reload');
    19                         });
    20                     }
    21                 }
    22                 $('#dg').datagrid("loading");
    23                 $("#searchForm").ajaxSubmit(options);
    24             } else {
    25                 $.messager.alert('錯誤', "請選擇Excel2007以上版本文件,擴展名:xlsx",'error');
    26             }
    27         }
    28     }
    Javacript方法
  3. 后台控制器Controller中接受文件流並傳給業務層做進一步處理,代碼參考
        @RequestMapping("upload.do")
        @ResponseBody
        public Result upload(HttpServletRequest req, @RequestParam(value = "filebox") MultipartFile file) {
            Result result = Result.getInstanceError();
            try {
                result = prodlineBugService.importByExcel(file);
            } catch (Exception e) {
                log.error("產線不良Excel導入異常:", e);
                result.setMsg(e.getMessage());
            }
            return result;
        }
  4. 業務層service
    public Result importByExcel(MultipartFile file) throws IOException {
            EasyExcel.read(file.getInputStream(), ProdlineBugVO.class, new ProdlineBugListener(this)).sheet().autoTrim(true)
                    .doRead();
            return Result.getInstanceSuccess();
        }
  5. 業務對象VO用注解標識一下列名。
      1 @ExcelIgnoreUnannotated
      2 public class ProdlineBugVO {
      3 
      4     /**
      5      * ID
      6      */
      7     @ExcelProperty(value = "ID")
      8     private Long id;
      9     /**
     10      * 期間(yyyy-mm)
     11      */
     12     private String yearMonth;
     13     /**
     14      * 供應商編碼
     15      */
     16     @ExcelProperty(value = "供應商編碼")
     17     private String supplierCode;
     18     /**
     19      * 物料編碼
     20      */
     21     @ExcelProperty(value = "物料編碼")
     22     private String itemNumber;
     23     /**
     24      * 包含Y 不包含N
     25      */
     26     @ExcelProperty(value = "不良數")
     27     private BigDecimal bugNum;
     28     /**
     29      * 總數
     30      */
     31     private BigDecimal totalNum;
     32     /**
     33      * 包含Y 不包含N
     34      */
     35     @ExcelProperty(value = "工單號")
     36     private String icmoCode;
     37     /**
     38      * 描述
     39      */
     40     @ExcelProperty(value = "描述")
     41     private String description;
     42     /**
     43      * 季度考核ID
     44      */
     45     private Long quarterExamineId;
     46     /**
     47      * 發生時間
     48      */
     49     @ExcelProperty(value = "發生日期")
     50     private Date actualTime;
     51 
     52     private String itemName;
     53     private String supplierName;
     54     /** excel行號 */
     55     private Integer rowIndex;
     56 
     57     /**
     58      * 設置 ID
     59      */
     60     public Long getId() {
     61         return id;
     62     }
     63 
     64     /**
     65      * 獲取 ID
     66      */
     67     public void setId(Long id) {
     68         this.id = id;
     69     }
     70 
     71     /**
     72      * 設置 期間(yyyy-mm)
     73      */
     74     public String getYearMonth() {
     75         return yearMonth;
     76     }
     77 
     78     /**
     79      * 獲取 期間(yyyy-mm)
     80      */
     81     public void setYearMonth(String yearMonth) {
     82         this.yearMonth = yearMonth;
     83     }
     84 
     85     /**
     86      * 設置 供應商編碼
     87      */
     88     public String getSupplierCode() {
     89         return supplierCode;
     90     }
     91 
     92     /**
     93      * 獲取 供應商編碼
     94      */
     95     public void setSupplierCode(String supplierCode) {
     96         this.supplierCode = supplierCode;
     97     }
     98 
     99     /**
    100      * 設置 物料編碼
    101      */
    102     public String getItemNumber() {
    103         return itemNumber;
    104     }
    105 
    106     /**
    107      * 獲取 物料編碼
    108      */
    109     public void setItemNumber(String itemNumber) {
    110         this.itemNumber = itemNumber;
    111     }
    112 
    113     public BigDecimal getBugNum() {
    114         return bugNum;
    115     }
    116 
    117     public void setBugNum(BigDecimal bugNum) {
    118         this.bugNum = bugNum;
    119     }
    120 
    121     public BigDecimal getTotalNum() {
    122         return totalNum;
    123     }
    124 
    125     public void setTotalNum(BigDecimal totalNum) {
    126         this.totalNum = totalNum;
    127     }
    128 
    129     /**
    130      * 設置 包含Y 不包含N
    131      */
    132     public String getIcmoCode() {
    133         return icmoCode;
    134     }
    135 
    136     /**
    137      * 獲取 包含Y 不包含N
    138      */
    139     public void setIcmoCode(String icmoCode) {
    140         this.icmoCode = icmoCode;
    141     }
    142 
    143     /**
    144      * 設置 描述
    145      */
    146     public String getDescription() {
    147         return description;
    148     }
    149 
    150     /**
    151      * 獲取 描述
    152      */
    153     public void setDescription(String description) {
    154         this.description = description;
    155     }
    156 
    157     /**
    158      * 設置 季度考核ID
    159      */
    160     public Long getQuarterExamineId() {
    161         return quarterExamineId;
    162     }
    163 
    164     /**
    165      * 獲取 季度考核ID
    166      */
    167     public void setQuarterExamineId(Long quarterExamineId) {
    168         this.quarterExamineId = quarterExamineId;
    169     }
    170 
    171     /**
    172      * 設置 發生時間
    173      */
    174     public Date getActualTime() {
    175         return actualTime;
    176     }
    177 
    178     /**
    179      * 獲取 發生時間
    180      */
    181     public void setActualTime(Date actualTime) {
    182         this.actualTime = actualTime;
    183     }
    184 
    185     /**
    186      * 創建人(郵箱)
    187      */
    188     private String createBy;
    189     /**
    190      * 創建時間
    191      */
    192     private Date createTime;
    193     /**
    194      * 更新人(郵箱)
    195      */
    196     private String updateBy;
    197     /**
    198      * 更新時間
    199      */
    200     private Date updateTime;
    201 
    202     public String getCreateBy() {
    203         return createBy;
    204     }
    205 
    206     public void setCreateBy(String createBy) {
    207         this.createBy = createBy;
    208     }
    209 
    210     public Date getCreateTime() {
    211         return createTime;
    212     }
    213 
    214     public void setCreateTime(Date createTime) {
    215         this.createTime = createTime;
    216     }
    217 
    218     public String getUpdateBy() {
    219         return updateBy;
    220     }
    221 
    222     public void setUpdateBy(String updateBy) {
    223         this.updateBy = updateBy;
    224     }
    225 
    226     public Date getUpdateTime() {
    227         return updateTime;
    228     }
    229 
    230     public void setUpdateTime(Date updateTime) {
    231         this.updateTime = updateTime;
    232     }
    233 
    234     public String getItemName() {
    235         return itemName;
    236     }
    237 
    238     public void setItemName(String itemName) {
    239         this.itemName = itemName;
    240     }
    241 
    242     public String getSupplierName() {
    243         return supplierName;
    244     }
    245 
    246     public void setSupplierName(String supplierName) {
    247         this.supplierName = supplierName;
    248     }
    249 
    250     public Integer getRowIndex() {
    251         return rowIndex;
    252     }
    253 
    254     public void setRowIndex(Integer rowIndex) {
    255         this.rowIndex = rowIndex;
    256     }
    257 }
    View Code
  6. 定義好Listener來調用保存方法。
     1 public class ProdlineBugListener extends AnalysisEventListener<ProdlineBugVO> {
     2     private Logger log = LoggerFactory.getLogger(this.getClass());
     3     
     4     /** 一次處理的數量,防止一次處理的過多造成oom */
     5     private static final int BATCH_COUNT = 5000;
     6     
     7     List<ProdlineBugVO> list = new ArrayList<ProdlineBugVO>();
     8     
     9     private ProdlineBugService prodlineBugService;
    10     
    11     public ProdlineBugListener() {
    12     }
    13 
    14     public ProdlineBugListener(ProdlineBugService prodlineBugService) {
    15         this.prodlineBugService = prodlineBugService;
    16     }
    17     
    18     @Override
    19     public void invoke(ProdlineBugVO data, AnalysisContext context) {
    20         data.setRowIndex(context.readRowHolder().getRowIndex() + 1);
    21         list.add(data);
    22         if (list.size() >= BATCH_COUNT) {
    23             // 達到BATCH_COUNT再處理,防止內存中存儲過大數據,容易OOM
    24             prodlineBugService.batchSave(list);
    25             list.clear();
    26         }
    27     }
    28 
    29     @Override
    30     public void doAfterAllAnalysed(AnalysisContext arg0) {
    31         // 這里也要保存數據,確保最后遺留的和不到batch_count的數據也存儲到數據庫
    32         prodlineBugService.batchSave(list);
    33     }
    34 }
    View Code

注意事項

  1. 事務問題:如果不想Excel處理過程中被分成好多比事務,那請將讀Excel的方法寫到有事務控制的業務層。這樣,當某一行內容校驗失敗,拋出異常,前面的操作就會回滾。
  2. 對於日期格式,可以用Date來接收。框架默認已經支持很多常用的數字格式,例如:"yyyy-MM-dd"等,但如果沒有解析成功,那就需要使用@DateTimeFormat("yyyy年MM月dd日")注解配置
  3. @ExcelProperty注解支持按列名或列索引來配置表頭,如果使用列名的方式,那即使列順序變更也不會影響讀數據。但千萬不要2種方式同時配置
  4. 對於少數Excel單元格內容格式不確定的情況(比如動態內容導入)。可能無法定義明確的VO值對象,可以使用Map<Integer, Object>來接受行內容。key是列索引。
    1. 如果單元格內容為空,map中不會有這個單元格對應的Entry,所以不要用EntrySet來循環
    2. 可以一開始就記錄好表頭的列數量,然后用這個列數量來循環Map,這樣就知道哪一列是空的了。
  5. 如果Excel中有空行,框架會自動跳過不會調用invoke方法。
  6. autoTrim如果是true,讀單元格內容時會自動trim。
  7. 框架默認第一行是表頭,數據是從第二行開始的。如果不是可以使用headRowNumber方法指定。
  8. 該框架已經解決了POI頭疼的性能問題而且簡化了很多Excel讀寫的代碼。更多功能可以參考官方github


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM