阿里easyExcel使用—下(easyExcel2.0.0 版本)

在這裏插入圖片描述
源碼地址:https://github.com/alibaba/easyexcel
升級版本 升級版本 升級版本
依賴

       <!--阿里easyExcel工具包-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.0.2</version>
        </dependency>

對應工具類

/**
 * @author  yy
 * @version 2.0
 * @date 2019/7/30 16:27
 * @deprecated 版本升級爲對應的2.0.0以上
 * 性能更加高效  導出數據更加穩定
 * 支持 64M內存1分鐘內讀取75M(46W行25列)
 **/
 @Component
public class ExcelUtil {
    /**
     * 導出 Excel :一個 sheet,帶表頭.
     *
     * @param response  HttpServletResponse
     * @param list      數據 list,每個元素爲一個 BaseRowModel
     * @param fileName  導出的文件名
     * @param sheetName 導入文件的 sheet 名
     * @param model     映射實體類,Excel 模型
     * @throws Exception 異常
     */


    public  void writeExcel(HttpServletResponse response, List<? extends Object> data,
                                  String fileName, String sheetName, Class model) throws Exception {

        // 頭的策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //設置表頭居中對齊
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        // 內容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //設置內容靠左對齊
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        // 這個策略是 頭是頭的樣式 內容是內容的樣式 其他的策略可以自己實現
        HorizontalCellStyleStrategy horizontalCellStyleStrategy =
                new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
        // 這裏 需要指定寫用哪個class去寫,然後寫到第一個sheet,名字爲模板 然後文件流會自動關閉
        EasyExcel.write(getOutputStream(fileName, response), model)
                .excelType(ExcelTypeEnum.XLSX)
                .sheet(sheetName)
                .registerWriteHandler(horizontalCellStyleStrategy)
                //最大長度自適應 目前沒有對應算法優化 建議註釋掉不用 會出bug
//                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .doWrite(data);

    }


    /**
     * 導出文件時爲Writer生成OutputStream.
     *
     * @param fileName 文件名
     * @param response response
     * @return ""
     */
    private  OutputStream getOutputStream(String fileName,
                                                HttpServletResponse response) throws Exception {
        try {
            fileName = URLEncoder.encode(fileName, "UTF-8");
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf8");
            response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".xlsx");
            response.setHeader("Pragma", "public");
            response.setHeader("Cache-Control", "no-store");
            response.addHeader("Cache-Control", "max-age=0");
            return response.getOutputStream();
        } catch (IOException e) {
            throw new Exception("導出excel表格失敗!", e);
        }
    }
    
     /**
     * 簡單的讀
     * @param fileName
     * @param clazz
     * @return
     */
 public List<?> simpleRead(String fileName, Class clazz) {
        // 有個很重要的點 DemoDataListener 不能被spring管理,要每次讀取excel都要new,然後裏面用到spring可以構造方法傳進去
        // 這裏 需要指定讀用哪個class去讀,然後讀取第一個sheet 文件流會自動關閉
        EasyExcel.read(fileName, clazz, new DataListener()).sheet().doRead();
        return new DataListener().saveData();
    }
    
***由於本身listener類沒有歸spring管理 所以無法獲取容器內部的bean實例*** 
 class DataListener extends AnalysisEventListener<User> {
 /**
     * 每隔5條存儲數據庫,實際使用中可以3000條,然後清理list ,方便內存回收
     */
    private  final int BATCH_COUNT = 10;
  private  List<User> list = new ArrayList<>();
    public List<User> getList() {
        return list;
    }
        /**
         * 這個每一條數據解析都會來調用
         *
         * @param data
         *            one row value. It is same as {@link AnalysisContext#readRowHolder()}
         * @param context
         */
        @Override
        public void invoke(User data, AnalysisContext context) {
            LOGGER.info("解析到一條數據:{}", JSON.toJSONString(data));
            list.add(data);
            // 達到BATCH_COUNT了,就需要對list進行清空,防止數據幾萬條數據在內存,容易OOM
            if (list.size() >= BATCH_COUNT) {
                saveData();
                // 存儲完成清理 list
                list.clear();
            }
        }

        /**
         * 所有數據解析完成了 都會來調用
         *
         * @param context
         */
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            // 這裏也要保存數據,確保最後遺留的數據也存儲到數據庫
//            saveData();
            LOGGER.info("所有數據解析完成!");
        }

        /**
         * 加上存儲數據庫
         */
        private List<?> saveData() {
            LOGGER.info("{}條數據,開始存儲數據庫!", list.size());
            return list;
        }
    }

實體映射Excelproperty 對應導出Excel表頭

@Data
@ColumnWidth(22)
@ContentRowHeight(15) //由於新版本並沒有對單元格設置默認值 
所以需要手動對單元格進行賦值
public class User extends BaseRowModel implements Serializable {
    /**
     * value: 單表頭如下     如果多表頭 則 @ExcelProperty(value = {"姓名1","姓名2","姓名3"}, index = 0)
     * index: 列的號, 0表示第一列
      * @ExcelIgnore   生成Excel忽略那個字段
     */
    /**
     * 姓名
     */

    @ExcelProperty(value = "姓名", index = 0)
    private String name;
    /**
     * 年齡
     */
    @ExcelProperty(value = "年齡", index = 1)
    private String age;
    /**
     * 性別
     */
    @ExcelProperty(value = "性別", index = 2)
    private String sex;
 
}

測試

   @Autowired
    private  ExcelUtil  excelUtil;
    public void testWright() {
        List<User> list = new HashList<>();
        for (int i = 0; i < 10000; i++) {
            User user = new User();
            user.setName(UUID.randomUUID().toString());
            user.setAge("10");
            user.setSex("男");
            list.add(user);
            }
            excelUtil.writeExcel(response, list, "test", "testsheet", user.getClass());
    }
 @Autowired
private  ExcelUtil  excelUtil;
public void testread(){
       User user = new User();
       List<User> list = excelUtil.simpleRead("報表路徑",user.getClass());   
       //打印每一個讀取的對象
        list.forEach(System.out::println);
    
    }

目前讀取報表的監聽器需要每次在讀取報表時重新new 所以不可以給spring容器管理 只能使用構造方法自己實例化 導致了無法獲取容器裏面的bean實例

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章