使用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);
}
这样就可以支持大数据量导出了。
使用POI导出EXCEL工具类并解决导出数据量大的问题的更多相关文章
- 导入导出Excel工具类ExcelUtil
前言 前段时间做的分布式集成平台项目中,许多模块都用到了导入导出Excel的功能,于是决定封装一个ExcelUtil类,专门用来处理Excel的导入和导出 本项目的持久化层用的是JPA(底层用hibe ...
- javaEE开发之导出excel工具类
web开发中,一个系统的普通需求也包含导出excel,一般採用POI做统计报表导出excel. 导出excel工具类: import java.io.FileOutputStream; import ...
- 自己封装的poi操作Excel工具类
自己封装的poi操作Excel工具类 在上一篇文章<使用poi读写Excel>中分享了一下poi操作Excel的简单示例,这次要分享一下我封装的一个Excel操作的工具类. 该工具类主要完 ...
- Java 通过Xml导出Excel文件,Java Excel 导出工具类,Java导出Excel工具类
Java 通过Xml导出Excel文件,Java Excel 导出工具类,Java导出Excel工具类 ============================== ©Copyright 蕃薯耀 20 ...
- java里poi操作Excel工具类【我改】
参考原文: https://www.cnblogs.com/yizhang/p/7244917.html 我改: package test; import java.io.File; import j ...
- 导出Excel工具类
import java.io.OutputStream; import java.lang.reflect.Method; import java.text.SimpleDateFormat; imp ...
- java导出excel工具类
java导出excel须要使用HSSFWorkbook这个类,须要导入poi-3.6-20091214.jar 工具类调用例如以下: package com.qlwb.business.util; i ...
- Java XSSF 导出excel 工具类
参数解释: title:导出excel标题.headers 导出到excel显示的列头. columns 对应数据库字段 .list 导出数据1.pox中添加依赖 <dependency> ...
- POI读取excel工具类 返回实体bean集合(xls,xlsx通用)
本文举个简单的实例 读取上图的 excel文件到 List<User>集合 首先 导入POi 相关 jar包 在pom.xml 加入 <!-- poi --> <depe ...
随机推荐
- 控制反转和依赖注入(对IOC,DI理解+案例)
理解 控制反转说的官方一点就是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度.其实就是一种设计思想,大概思想就是把设计好的对象交给容器控制,而不是在你内部直接控制. 依赖注入是控制反 ...
- B/S 端基于 HTML5 + WebGL 的 VR 3D 机房数据中心可视化
前言 在 3D 机房数据中心可视化应用中,随着视频监控联网系统的不断普及和发展, 网络摄像机更多的应用于监控系统中,尤其是高清时代的来临,更加快了网络摄像机的发展和应用. 在监控摄像机数量的不断庞大的 ...
- 利用phar实行php反序列化命令执行漏洞复现
利用phar实行php反序列化命令执行(测试环境复现) 前言 一般说到反序列化漏洞,第一反应都是unserialize()函数.然而安全研究员Sam Thomas分享了议题”It’s a PHP un ...
- CSS3、jQuery实现3D翻书动画
使用CSS3 ,jQuery实现点击翻书动画效果,完整效果可在firefox中查看 HTML <div class="desktop"> <div class=& ...
- HDFS概述(一)
HDFS概述(一) 1. HDFS产出的背景及定义 1.1 HDFS产生的背景 随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需 ...
- vue-cli2、vue-cli3脚手架详细讲解
前言: vue脚手架指的是vue-cli它是vue官方提供的一个快速构建单页面(SPA)环境配置的工具,cli 就是(command-line-interface ) 命令行界面 .vue-cli是 ...
- 百万年薪python之路 -- 并发编程之 多进程 一
并发编程之 多进程 一. multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大 ...
- solr学习篇(二) solr 分词器篇
关于solr7.4搭建与配置可以参考 solr7.4 安装配置篇 在这里我们探讨一下分词的配置 目录 关于分词 配置分词 验证成功 1.关于分词 1.分词是指将一个中文词语拆成若干个词,提供搜索引擎 ...
- 微信小程序中的canvas基础应用
学了东西还是要记录一下,刚入职的小萌新啊,运气好分到一个项目不是很急的组原以为时间多了可以多学一些东西,但是发现好像不知道从哪里开始下手,我太南了.... 看旁边的实习生同事一直在搞canvas,自己 ...
- Java基础(十八)集合(5)Queue集合
队列是只能在尾部添加元素,同时只能在头部删除元素的数据结构.队列的原则就是“先进先出”. Queue接口是Collection接口的最后一个子接口. Queue接口是队列接口,而Deque接口是Que ...