使用POI導出EXCEL工具類並解決導出數據量大的問題

POI導出工具類

  工做中經常會遇到一些圖表須要導出的功能,在這裏本身寫了一個工具類方便之後使用(使用POI實現)。java

項目依賴數據庫

 

       <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.6</version>
        </dependency>        

 

package com.adcc.eoss.util; import org.apache.poi.hssf.usermodel.*; import javax.servlet.http.HttpServletResponse; import java.io.OutputStream; import java.io.UnsupportedEncodingException; /** * Created by LMQ on 2019/3/18. */
public class ExcelUtil { public static HSSFWorkbook getHSSFWorkbook(String sheetName, String[] title, String[][] values) { return getHSSFWorkbook(sheetName, title, values, null); } /** * 導出Excel * * @param sheetName sheet名稱 * @param title 標題 * @param values 內容 * @param wb HSSFWorkbook對象 * @return
     */
    public static HSSFWorkbook getHSSFWorkbook(String sheetName, String[] title, String[][] values, HSSFWorkbook wb) { // 第一步,建立一個HSSFWorkbook,對應一個Excel文件
        if (wb == null) { wb = new HSSFWorkbook(); } // 第二步,在workbook中添加一個sheet,對應Excel文件中的sheet
        HSSFSheet sheet = wb.createSheet(sheetName); // 第三步,在sheet中添加表頭第0行,注意老版本poi對Excel的行數列數有限制
        HSSFRow row = sheet.createRow(0); // 第四步,建立單元格,並設置值表頭 設置表頭居中
        HSSFCellStyle style = wb.createCellStyle(); style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 建立一個居中格式
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 建立一個垂直居中格式 //聲明列對象
        HSSFCell cell = null; //建立標題
        for (int i = 0; i < title.length; i++) { cell = row.createCell(i); cell.getCellStyle().setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); cell.getCellStyle().setAlignment(HSSFCellStyle.ALIGN_CENTER); cell.setCellValue(title[i]); cell.setCellStyle(style); } //建立內容
        for (int i = 0; i < values.length; i++) { row = sheet.createRow(i + 1); for (int j = 0; j < values[i].length; j++) { //將內容按順序賦給對應的列對象
 row.createCell(j).setCellValue(values[i][j]); } } return wb; } //響應到客戶端
    public static void returnClient(HttpServletResponse response, String fileName, HSSFWorkbook wb) { try { setResponseHeader(response, fileName); OutputStream os = response.getOutputStream(); wb.write(os); os.flush(); os.close(); } catch (Exception e) { e.printStackTrace(); } } //發送響應流方法
    public static void setResponseHeader(HttpServletResponse response, String fileName) { try { try { fileName = new String(fileName.getBytes(), "ISO8859-1"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block
 e.printStackTrace(); } response.setContentType("application/octet-stream;charset=ISO8859-1"); response.setHeader("Content-Disposition", "attachment;filename=" + fileName); response.addHeader("Pargam", "no-cache"); response.addHeader("Cache-Control", "no-cache"); } catch (Exception ex) { ex.printStackTrace(); } } }

經過這個工具類咱們只須要傳遞對應參數就可以實現簡單的EXCEL導出功能。apache

下面是一個導出的例子瀏覽器

 /** * 導出用戶信息 * * @param map * @param response */
    public void exportToExcel(Map<String, Object> map, HttpServletResponse response) throws Exception { // 查詢獲得用戶數據
        List<UserVO> vos = findByConditionReturnExcel(map); // 定義表格頭信息
        String[] titles = new String[]{"用戶名稱", "狀態", "建立時間", "建立人", "最後登陸時間", "所在公司"}; // 爲表格內容賦值
        String[][] values = new String[vos.size()][titles.length]; if (vos != null && vos.size() > 0) { for (int i = 0; i < vos.size(); i++) { values[i][0] = vos.get(i).getUserName(); values[i][1] = vos.get(i).getUserState(); values[i][2] = vos.get(i).getCreateDate(); values[i][3] = vos.get(i).getCreateUser(); values[i][4] = vos.get(i).getLastLoginTime(); values[i][5] = vos.get(i).getSourceCompanyName(); } } // 導出
        ExcelUtil.returnClient(response, "user.xls", ExcelUtil.getHSSFWorkbook("用戶管理", titles, values)); }
HttpServletResponse 對象可在控制層經過參數傳遞進來便可。

那麼問題來了,對於不是經過客戶端瀏覽器的導出操做,咱們就沒法用
HttpServletResponse,其實這也是我在作一個統計工具的時候遇到的問題,
這個統計用的是圖形界面開發SWT實現。那麼咱們就沒法用這種客戶端響應的方式實現導出。那麼這個工具類不是就沒用了?當時查了網上的資料,其實
只需更改響應方式便可。後來我用輸出流修改了這個工具類。改動以下(由於只是個統計小工具也就沒用到緩衝流之類的,只是簡單作了輸出)
fileName可定義具體的輸出位置如: 'D:/統計/'+文件名
 
 //經過輸出流響應
    public static void returnClient(String fileName, HSSFWorkbook wb) throws Exception { FileOutputStream os = null; try { File file = new File(fileName); os = new FileOutputStream(file); wb.write(os); os.flush(); os.close(); } catch (Exception e) { throw e; } finally { if (os != null) { try { // 關閉流
 os.close(); } catch (IOException e) { throw e; } } } }

導出數據量大的解決辦法

使用poi導出excel的時候若是數據過多,超過65535條會報錯,由於excel2003一個sheet表最多導出65535條,excel2007是10萬4000多條限制。app

Invalid row number (65536) outside allowable range (0..65535)
解決方案:一個sheet最多能夠導出65535條,咱們能夠分紅多個sheet導出。
當時我寫了一個特別蠢的方法,可是也算實現的功能。下面分享一下個人辦法
當時是這樣想的,好比從數據庫查詢出一百萬條數據,我把這數據分紅多份,用同一個HSSFWorkbook對象,執行工具類中getHSSFWorkbook方法不就好了
因而就有了如下實現(主要是懶得改工具類-_-)
 
 /** * 將一個集合拆分紅多個 * * @param list 須要拆分的集合 * @param num 每一個集合的數量 * @return
     */
    public Map<String, List<CDM>> splitList(List<CDM> list, Integer num) { // list 長度
        int listSize = list.size(); // 用map來存放集合
        HashMap<String, List<CDM>> listHashMap = new HashMap<String, List<CDM>>(); // 單個集合對象
        List<CDM> childList = new ArrayList<>(); // 遍歷要拆分集合按定義的num數量存放到childList
        for (int i = 0; i < listSize; i++) { childList.add(list.get(i)); if (((i + 1) % num == 0) || (i + 1 == listSize)) { // 存入map
 listHashMap.put(String.valueOf(i), childList); childList = new ArrayList<>(); } } return listHashMap; }
以上是拆分集合的方法,經過這個方法便可實現集合拆分,以後在業務代碼這樣寫就好了
wb爲HSSFWorkbook對象,咱們在代碼裏把它在循環外聲明就行 HSSFWorkbook wb = new HSSFWorkbook();
 if (list.size() > 65535) {
          // 每一個小集合放60000萬個,個數能夠本身定義 Map
<String, List<CDM>> childListMap = splitList(list, 60000);
          // 循環map,循環爲wb添加sheet wb也就是咱們的HSSFWorkbook對象
for (Map.Entry<String, List<CDM>> entry : childListMap.entrySet()) { String[][] values = new String[entry.getValue().size()][titles.length]; for (int i = 0; i < entry.getValue().size(); i++) { values[i][0] = entry.getValue().get(i).getId(); values[i][1] = entry.getValue().get(i).getName();    //....
            } wb
= ExcelUtil.getHSSFWorkbook("各個區局CDM點播數據準確率統計" + entry.getKey(), titles, values, wb); }

這樣就能夠支持大數據量導出了。ide

感受這個解決辦法有點蠢,等有時間修改一下工具類再進行補充。工具

相關文章
相關標籤/搜索