上篇文章已經介紹Excel能夠分爲Excel2003和Excel2007兩種版本,Excel2003在POI中使用HSSF對象,一個sheet最多容許65536條數據,處理較少數據時可使用,可是處理百萬數據時Excel2003確定容納不了;Excel2007在POI中使用XSSF對象,最多容許一個sheet存儲1048576條數據,表示其已經能夠支持百萬數據,可是在實際運行可能中還存在問題,緣由是POI報表所產生的對象,單元格對象,字體對象,都不會銷燬,致使了可能存在OutOfMemoryError(OOM)內存溢出風險。java
對於百萬數據Excel的導出,基本只限於討論Excel2007版本的使用方法。ApachePOI提供三種方式解決大數據量的數據導入導出:git
在互聯網時代,百萬數據常常產生,有多種多樣的緣由須要數據導出github
使用POI的XSSFWORK對象進行導出Excel報表,是將全部的數據一次性到單元格對象,並保存到內存中,當單元格所有建立完成纔會一次性寫入到Excel進行導出。當達到百萬級別的數據導出時,隨着單元格對象的不斷建立,內存中的數據愈來愈多,直到OOM。POI的SXSSFWORK對象,是專門用於處理大數據量的Excel導出的。apache
在實例化SXSSFWork對象時,能夠指定內存中所產生的POI對象數量(默認100),一旦內存對象個數達到指定數量,就將內存中的數據寫入到磁盤,就能夠將內存中數據進行銷燬,以此循環直到Excel導出完成app
仍是以用戶數據爲例子xss
在FileUtil中添加ide
對以前的作了一些小改動字體
package com.cn.greemes.common.util; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.poi.excel.BigExcelWriter; import cn.hutool.poi.excel.ExcelUtil; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.streaming.SXSSFSheet; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.net.URLEncoder; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; /** * 文件操做 */ public class FileUtil { public static final String SYS_TEM_DIR =System.getProperty("java.io.tmpdir")+ File.separator; public void downloadExcel(List<Map<String, String>> list, HttpServletResponse response) throws IOException { String tempPath = SYS_TEM_DIR + IdUtil.fastSimpleUUID() + ".xlsx"; File file = new File(tempPath); BigExcelWriter writer = ExcelUtil.getBigWriter(file); // 一次性寫出內容,使用默認樣式,強制輸出標題 writer.write(list, true); SXSSFSheet sheet = (SXSSFSheet)writer.getSheet(); //上面須要強轉SXSSFSheet 否則沒有trackAllColumnsForAutoSizing方法 sheet.trackAllColumnsForAutoSizing(); //列寬自適應 // writer.autoSizeColumnAll(); //response爲HttpServletResponse對象 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"); //test.xls是彈出下載對話框的文件名,不能爲中文,中文請自行編碼 response.setHeader("Content-Disposition", "attachment;filename=file.xlsx"); ServletOutputStream out = response.getOutputStream(); // 終止後刪除臨時文件 file.deleteOnExit(); writer.flush(out, true); //此處記得關閉輸出Servlet流 IoUtil.close(out); } public void downloadExcelBySXSSF(List<Map<String, String>> list, HttpServletResponse response) throws IOException { String tempPath = SYS_TEM_DIR + IdUtil.fastSimpleUUID() + ".xlsx"; File file = new File(tempPath); //2.建立工做簿 SXSSFWorkbook workbook = new SXSSFWorkbook(); //3.構造sheet Sheet sheet =workbook.createSheet(); //建立表頭 Row row = sheet.createRow(0); Map<String,String> mapfirst = list.get(0); String listHead = null; AtomicInteger headersAi = new AtomicInteger(); for (String key : mapfirst.keySet()) { Cell cell = row.createCell(headersAi.getAndIncrement()); cell.setCellValue(key); } AtomicInteger datasAi = new AtomicInteger(1); Cell cell =null; for(Map<String, String> map : list){ Row dataRow = sheet.createRow(datasAi.getAndIncrement()); int i=0; for (String key : map.keySet()) { Cell cell1 = dataRow.createCell(datasAi.getAndIncrement()); String value= (String)map.get(key); cell = dataRow.createCell(i); cell1.setCellValue(value); i++; } } String fileName = URLEncoder.encode("用戶信息.xlsx", "UTF-8"); response.setContentType("application/octet-stream"); response.setHeader("content-disposition", "attachment;filename=" + new String(fileName.getBytes("ISO8859-1"))); response.setHeader("filename", fileName); workbook.write(response.getOutputStream()); } }
@ApiOperation("導出用戶數據") @RequestMapping(value = "/export2", method = RequestMethod.GET) @ResponseBody public void export2(HttpServletResponse response, @RequestParam(value = "keyword", required = false) String keyword, @RequestParam(value = "pageSize", defaultValue = "5") Integer pageSize, @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum) throws UnsupportedEncodingException, IOException { Page<MesAdmin> adminList = adminService.list(keyword, pageSize, pageNum); List<Map<String,String>> list = new ArrayList(); //由於只有七條數據,因此作了屢次循環添加數據 for(int i=0;i<149795;i++) { for (MesAdmin umsAdmin : adminList.getRecords()) { Map<String, String> map = new HashMap<>(6); DateFormat d1 = DateFormat.getDateInstance(); map.put("姓名", umsAdmin.getUsername()); map.put("郵箱", umsAdmin.getEmail()); map.put("暱稱", umsAdmin.getNickName()); map.put("備註信息", umsAdmin.getNote()); map.put("建立時間", d1.format( umsAdmin.getCreateTime())); String loginTime =""; if(umsAdmin.getLoginTime()!=null){ loginTime=d1.format( umsAdmin.getLoginTime()); } map.put("最後登陸時間",loginTime ); list.add(map); } } fileUtil.downloadExcelBySXSSF(list,response); }
原本要介紹數據的導出,但是發現百萬級別的數據導出也須要介紹一下,明天介紹數據的導出大數據
github地址:https://github.com/bangbangzhou/greemes/tree/masterui