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


POI導出工具類

  工作中常常會遇到一些圖表需要導出的功能,在這里自己寫了一個工具類方便以后使用(使用POI實現)。

項目依賴

 

       <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導出功能。

下面是一個導出的例子

 /** * 導出用戶信息 * * @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多條限制。

Invalid row number (65536) outside allowable range (0..65535)
解決方案:一個sheet最多可以導出65535條,我們可以分成多個sheet導出。
當時我寫了一個特別low的方法,但是也算實現的功能。下面分享一下我的辦法
當時是這樣想的,比如從數據庫查詢出一百萬條數據,我把這數據分成多份,用同一個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("統計" + entry.getKey(), titles, values, wb); }

這樣就可以支持大數據量導出了。

 


 
        
 
        

 


免責聲明!

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



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