POI导出Excel,每个Excel中有多个sheet
通过Zip导出多个Excel的压缩文件。
假如项目部署到服务器上,就无法直接下载到本地桌面,需要先下载到服务器的某个文件夹,再使用response通过浏览器下载到客户端的桌面。
假如需要同时下载多个Excel,response请求只满足一次下载一个文件,这是需要先将多个Excel文件下载到同一个文件夹下,再将此文件夹压缩,之后下载压缩文件。
根据别人方法总结的,在此记录一下。
参考别人的:java将不同模块数据导出到多个excel并压缩下载
private ExportToExcelByPOI exportToExcelByPOI{
private final static Logger logger = LoggerFactory.getLogger(BasyybqkckController.class);
/**
* 工具类
*
* @param workbook
* @param sheetNum 第几个sheet
* @param sheetTitle sheet的名称
* @param headers 表头,可生成复杂的表头
* @param fieldName 表头对饮的字段名
* @param list 数据
* @param type 用来分辨不同页面的导出
* @throws Exception
*/
public void exportExcelPoiTool(SXSSFWorkbook workbook, int sheetNum, String sheetTitle, String[][] headers, String[] fieldName,
List<HashMap<String, Object>> list, String type) throws Exception {
//设计表头
int mergerNum = 0; //合并数
//表头占几行,正文内容从表头之下开始
int headersLen = headers.length;
// 第一步,创建一个webbook,对应一个Excel以xsl为扩展名文件
//SXSSFSheet sheet = (SXSSFSheet) workbook.createSheet();
Sheet sheet = workbook.createSheet(sheetTitle);
workbook.setSheetName(sheetNum, sheetTitle);
// 冻结最左边的两列、冻结最上面的一行
// 即:滚动横向滚动条时,左边的第一、二列固定不动;滚动纵向滚动条时,上面的第一,二,三行固定不动。
//sheet.createFreezePane(2, 3);
//设置列宽度大小
// sheet.setDefaultColumnWidth((short) 30);
//第二步, 生成表格第一行的样式和字体
// 设置并获取到需要的样式
XSSFCellStyle xssfCellStyleHeader = getAndSetXSSFCellStyleHeader(workbook);
XSSFCellStyle xssfCellStyleOne = getAndSetXSSFCellStyleOne(workbook);
XSSFCellStyle xssfCellStyleTwo = getAndSetXSSFCellStyleTwo(workbook);
// 产生表格标题行
// 循环创建header单元格(根据实际情况灵活创建即可)
//给单元格设置值
for (int i = 0; i < headers.length; i++) {
//XSSFRow row = sheet.createRow(i);
Row row = sheet.createRow(i);
row.setHeight((short) 700);
for (int j = 0; j < headers[i].length; j++) {
//XSSFCell cell = row.createCell(j);
Cell cell = row.createCell(j);
cell.setCellStyle(xssfCellStyleHeader);
cell.setCellValue(headers[i][j]);
}
}
Map<Integer, List<Integer>> jumpMap = new HashMap<Integer, List<Integer>>(); // 合并行时要跳过的行列
//合并列
for (int i = 0; i < headers[headers.length - 1].length; i++) {
if ("".equals(headers[headers.length - 1][i])) {
for (int j = headers.length - 2; j >= 0; j--) {
if (!"".equals(headers[j][i])) {
sheet.addMergedRegion(new CellRangeAddress(j, headers.length - 1, i, i)); // 合并单元格
break;
} else {
if (jumpMap.containsKey(j)) {
List<Integer> jumpList = jumpMap.get(j);
jumpList.add(i);
jumpMap.put(j, jumpList);
} else {
List<Integer> jumpList = new ArrayList<Integer>();
jumpList.add(i);
jumpMap.put(j, jumpList);
}
}
}
}
}
//合并行
for (int i = 0; i < headers.length - 1; i++) {
for (int j = 0; j < headers[i].length; j++) {
List<Integer> jumpList = jumpMap.get(i);
if (jumpList == null || (jumpList != null && !jumpList.contains(j))) {
if ("".equals(headers[i][j])) {
mergerNum++;
if (mergerNum != 0 && j == (headers[i].length - 1)) {
sheet.addMergedRegion(new CellRangeAddress(i, i, j - mergerNum, j)); // 合并单元格
mergerNum = 0;
}
} else {
if (mergerNum != 0) {
sheet.addMergedRegion(new CellRangeAddress(i, i, j - mergerNum - 1, j - 1)); // 合并单元格
mergerNum = 0;
}
}
}
}
}
// 第三步:遍历集合数据,产生数据行,开始插入数据
// 遍历创建行,导出数据
if (list.size() > 0) {
for (int rownum = 0; rownum < list.size(); rownum++) {
// 从第四行开始有数据,前三行是表头
Row row = sheet.createRow(rownum + headersLen);
// 循环创建单元格
for (int cellnum = 0; cellnum < fieldName.length; cellnum++) {
Cell cell = row.createCell(cellnum);
// 根据行数,设置该行内的单元格样式
cell.setCellStyle(xssfCellStyleOne);
if (fieldName[cellnum].equals("xh")) {
cell.setCellValue(rownum + 1);//序号
} else {
cell.setCellValue(list.get(rownum).get(fieldName[cellnum]) + "");
}
}
}
}
//设置内容的sheet
setSheet(sheet);
// 即:滚动横向滚动条时,左边的第一、二列固定不动;滚动纵向滚动条时,上面的第一,二,三行固定不动。
sheet.createFreezePane(2, 3);
//sheet.createFreezePane(2, headersLen);
/**
* 导出到本机桌面
*
* @param list,要导出的数据,一条数据对应一个sheet。 一条数据中包含多条要导出的数据,格式如下:
* List<List<Map<String,Object>>> list
* @param headers 表头,表头有一行的,两行的,三行的
* @param fieldName 表头对应的字段名称
* @param fileName 文件名
* @param sheetTile sheet名称,一个sheetTitle对应list中的一条数据
* @param type 用来分辨不同的导出:
* @return
*/
public int exportToExcelByPoi_pc(List list, String[][] headers, String[] fieldName,
String fileName, String[] sheetTile, String type) {
//获取桌面路径,用于下载文件
FileSystemView fsv = FileSystemView.getFileSystemView();
File com = fsv.getHomeDirectory();
// 导出的excel,全文件名
//final String excelExportDestfilepath = com + "/" + map.get("fileName");
final String excelExportDestfilepath = com + "/" + "/" + fileName + ".xlsx";
ExportToExcelByPOI excelExport = null;
// 用于导出多个sheet
excelExport = new ExportToExcelByPOI();
FileOutputStream fos = null;
SXSSFWorkbook sxssfWorkbook = null;
try {
/// -> 从数据库中查询出要进行excel导出的数据
long startTime0 = System.currentTimeMillis();
long endTime0 = System.currentTimeMillis();
logger.info("查询数据总耗时:{} 毫秒; list数量为 {}", endTime0 - startTime0, list.size());
/// -> excel到处逻辑
long startTime = System.currentTimeMillis();
// 获取SXSSFWorkbook实例
sxssfWorkbook = new SXSSFWorkbook();
// sheet名称
//Sheet sheet = sxssfWorkbook.createSheet(fileName);
// 创建第一行,作为header表头;从第二行开始
int ts = sheetTile.length;
for (int i = 0; i < sheetTile.length; i++) {
excelExport.exportExcelPoiTool(sxssfWorkbook, i, sheetTile[i], headers, fieldName, (List<HashMap<String, Object>>) list.get(i), type);
}
//在后面设置sheet
//setSheet(sheet);
fos = new FileOutputStream(excelExportDestfilepath);
sxssfWorkbook.write(fos);
long endTime = System.currentTimeMillis();
logger.info("数据全部导出至excel总耗时:{} 毫秒!", endTime - startTime, list.size());
} catch (Exception e) {
logger.error("发生异常咯!", e);
} finally {
try {
if (sxssfWorkbook != null)
// dispose of temporary files backing this workbook on disk -> 处
// 理SXSSFWorkbook导出excel时,产生的临时文件
sxssfWorkbook.dispose();
if (fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return 1;
}
与导出到本机桌面不同的是的地方就是多了一个文件下载,
1、先将文件下载到服务器的桌面,
2、然后再将服务器上的文件通过浏览器下载到客户端,
3、最后删除服务器上的文件
/**
* 服务器导出到本机
*
* @param list,要导出的数据,一条数据对应一个sheet。 一条数据中包含多条要导出的数据,格式如下:
* List<List<Map<String,Object>>> list
* @param headers 表头,表头有一行的,两行的,三行的
* @param fieldName 表头对应的字段名称
* @param fileName 文件名
* @param sheetTile sheet名称,一个sheetTitle对应list中的一条数据
* @param type 用来分辨不同的导出:
* @param response
* @return
*/
public void exportToExcelByPoi(List list, String[][] headers, String[] fieldName,
String fileName, String[] sheetTile, String type, HttpServletResponse response) {
//获取桌面路径,用于下载文件
FileSystemView fsv = FileSystemView.getFileSystemView();
File com = fsv.getHomeDirectory();
// 导出的excel,全文件名
//final String excelExportDestfilepath = filePath + fileName + ".xlsx";
final String excelExportDestfilepath = com + "/" + "/" + fileName + ".xlsx";
ExportToExcelByPOI excelExport = null;
// 用于导出多个sheet
excelExport = new ExportToExcelByPOI();
FileOutputStream fos = null;
SXSSFWorkbook sxssfWorkbook = null;
try {
/// -> 从数据库中查询出要进行excel导出的数据
long startTime0 = System.currentTimeMillis();
long endTime0 = System.currentTimeMillis();
logger.info("查询数据总耗时:{} 毫秒; list数量为 {}", endTime0 - startTime0, list.size());
/// -> excel到处逻辑
long startTime = System.currentTimeMillis();
// 获取SXSSFWorkbook实例
sxssfWorkbook = new SXSSFWorkbook();
// sheet名称
//Sheet sheet = sxssfWorkbook.createSheet(fileName);
//导出
for (int i = 0; i < sheetTile.length; i++) {
excelExport.exportExcelPoiTool(sxssfWorkbook, i, sheetTile[i], headers, fieldName, (List<HashMap<String, Object>>) list.get(i), type);
}
//在后面设置sheet
//setSheet(sheet);
fos = new FileOutputStream(excelExportDestfilepath);
sxssfWorkbook.write(fos);
// 以下是与导出到本机桌面不同的地方
// 文件下载
String excelName = fileName + ".xlsx";
InputStream inputStream = null;
ServletOutputStream outServletOutputStream = null;
// 输出文档路径及名称
File outFile = new File(excelExportDestfilepath);
inputStream = new FileInputStream(excelExportDestfilepath);
response.setCharacterEncoding("utf-8");
response.setContentType("application/msexcel");
//response.addHeader("Content-Disposition", "attachment;filename=我" + "你" + ".xlsx");
//response.setHeader("Content-Disposition", "attachment; filename=" + java.net.URLEncoder.encode(fileName, "UTF-8"));
//防止文件名中文乱码
response.setHeader("Content-Disposition", "attachment;filename=" +
new String(excelName.getBytes("GBK"), "ISO8859-1"));
outServletOutputStream = response.getOutputStream();
byte[] buffer = new byte[512];
int bytesToRead = -1;
while ((bytesToRead = inputStream.read(buffer)) != -1) {
outServletOutputStream.write(buffer, 0, bytesToRead);
}
// 流关闭后
inputStream.close();
//删除服务器上下载的文件
outFile.delete();
long endTime = System.currentTimeMillis();
logger.info("数据全部导出至excel总耗时:{} 毫秒!", endTime - startTime, list.size());
} catch (Exception e) {
logger.error("发生异常咯!", e);
} finally {
try {
if (sxssfWorkbook != null)
// dispose of temporary files backing this workbook on disk -> 处
// 理SXSSFWorkbook导出excel时,产生的临时文件
sxssfWorkbook.dispose();
if (fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
调用exportToExcelByPoi方法,进行导出
@Autowired
private ExportToExcelByPOI exportToExcelByPOI;
@RequestMapping(value = "/exportToExcelByPoi", method = RequestMethod.GET)
@ResponseBody
public void exportPoi(@RequestParam Map<String, Object> map, HttpServletRequest request, HttpServletResponse response) {
//生成复杂的表头
String[][] propertyDes = {{"序号","疾病", "例数", "", "", "死亡率", "", "", "药占比", "", "", "材料占比",
"", "", "药品和材料占比", "", "", "平均住院日", "", "", "平均住院费用", "", ""},
{"","", "本期值", "上期值", "", "本期值", "上期值", "", "本期值", "上期值", "", "本期值", "上期值",
"", "本期值", "上期值", "", "本期值", "上期值", "", "本期值", "上期值", ""},
{"","", "", "值", "±%", "", "值", "±%", "", "值", "±%", "", "值", "±%", "", "值", "±%",
"", "值", "±%", "", "值", "±%"}};
// 表头对应的字段名称
String[] fieldName = {"xh","name", "ls", "lsPrev", "lsRadio",
"swl", "swlPrev", "swlRadio", "yzb", "yzbPrev", "yzbRadio",
"clzb", "clzbPrev", "clzbRadio", "ypyclzb", "ypyclzbPrev", "ypyclzbRadio",
"pjzyr", "pjzyrPrev", "pjzyrRadio", "pjzyfy", "pjzyfyPrev","pjzyfyRadio"};
// 查询要导出的数据
List<HashMap<String, Object>> list = service.getData(map);
//将数据转换成要导出的格式,这里根据情况而定
List<HashMap<String, Object>> listData = conversionListData(list);
// sheet的名称,要导出多个sheet的话,就会对应多个
String[] sheetTile={fileName};
List listExcel=new ArrayList();
// 一个sheetTitle,对应一个listData,多个SheetTitle,对应多个ListData。这里是一个sheetTitle对应一个ListData。
listExcel.add(listData);
//多个的话如下:
String[] sheetTile = {"济南市", "青岛市", "淄博市", "枣庄市", "东营市", "烟台市", "潍坊市", "济宁市", "泰安市",
"威海市", "日照市", "临沂市", "德州市", "聊城市", "滨州市", "菏泽市"};
for (int i = 0; i < sheetTile.length; i++) {
List param = new ArrayList();
// 分别查询16个地级市的数据
List<HashMap<String, Object>> list = service.getData(map);
//将数据转换为导出的格式
List<HashMap<String, Object>> listData = conversionListData(list);
// 把数据放到数组中,数组中放的是16个地级市的数据
listExcel.add(listData );
}
exportToExcelByPOI.exportToExcelByPoi(listExcel,propertyDes,fieldName,fileName,sheetTile,response);
}
以下代码:将多个Excel压缩成一个文件进行导出
/**
* 服务器导出多个Excel的Zip文件到客户端
*
*
* @param list,要导出的数据,一条数据对应一个sheet。 一条数据中包含多条要导出的数据,格式如下:
* List<List<Map<String,Object>>> list
* @param headers 表头,表头有一行的,两行的,三行的
* @param fieldName 表头对应的字段名称
* @param fileName 文件名
* @param sheetTile sheet名称,一个sheetTitle对应list中的一条数据
* @param type 用来分辨不同的导出:
* @param response
* @return
*/
public void exportToExcelByPoi_zip(List list, String[][] headers, String[] fieldName,
String[] fileName, String[] sheetTile, String type,
HttpServletResponse response, HttpServletRequest request) {
// 生成的excel表格路径
final List<String> fileNameList = new ArrayList<String>();
// list中包括多个excel的信息
for (int i = 0; i < list.size(); i++) {
List ListQuarter = (List) list.get(i);
// 将数据导入到excel表格中,并将生成的表格路径添加到fileNameList中
ExportExcelZipUtils.toExcelForZip(ListQuarter,headers,fieldName,fileName[i],sheetTile,type,response,request,fileNameList);
}
// 将生成的多个excel表格路径压缩成zip格式文件,并返回生成的临时zip文件路径
final String zipFilePath = ExportExcelZipUtils.toZipFiles(request, fileNameList, "批量导出excel文件.zip");
// zip文件创建成功
if (!StringUtils.isEmpty(zipFilePath)) {
try {
// 设置response头
ExportExcelZipUtils.setResponseHeader(response, "批量导出excel文件.zip");
// 下载
ExportExcelZipUtils.downloadZip(response.getOutputStream(), zipFilePath);
} catch (final IOException e) {
logger.info("get outputStream from response failed");
}
}
}
public class ExportExcelZipUtils {
private final static org.slf4j.Logger logger = LoggerFactory.getLogger(ExportToExcelByPOI.class);
/**
* 设置excel压缩文件导出时的请求头
* @param response
* @param fileName:多个excel的压缩文件名
*/
public static void setResponseHeader(final HttpServletResponse response, final String fileName) {
logger.info("begin to set response header");
try {
response.reset();
response.setContentType("application/octet-stream");
response.setCharacterEncoding("UTF-8");
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
response.addHeader("Pargam", "no-cache");
response.addHeader("Cache-Control", "no-cache");
logger.info("set response header successfully");
} catch (final Exception e) {
logger.error("set response header failed", e);
}
}
/**
* 生成excel文件
* @param list
* @param headers
* @param fieldName
* @param fileName
* @param sheetTile
* @param type
* @param response
* @param request
* @param fileNameList
*/
public static void toExcelForZip(List list, String[][] headers, String[] fieldName,
String fileName, String[] sheetTile, String type,
HttpServletResponse response, HttpServletRequest request,
List<String> fileNameList) {
final File dirFile = new File(request.getRealPath(File.separator + "excel") + File.separator);
if (!dirFile.exists()) {
dirFile.mkdirs();
}
final String file = request.getRealPath(File.separator + "excel") + File.separator + fileName + ".xlsx";
//获取桌面路径,用于下载文件
FileSystemView fsv = FileSystemView.getFileSystemView();
File com = fsv.getHomeDirectory();
// 导出的excel,全文件名
final String excelExportDestfilepath = com + "/" + "/" + fileName + ".xlsx";
ExportToExcelByPOI excelExport = null;
// 用于导出多个sheet
excelExport = new ExportToExcelByPOI();
FileOutputStream fos = null;
SXSSFWorkbook sxssfWorkbook = null;
try {
fos = new FileOutputStream(file);//为压缩文件做准备
/// -> 从数据库中查询出要进行excel导出的数据
long startTime0 = System.currentTimeMillis();
long endTime0 = System.currentTimeMillis();
logger.info("查询数据总耗时:{} 毫秒; list数量为 {}", endTime0 - startTime0, list.size());
/// -> excel到处逻辑
long startTime = System.currentTimeMillis();
// 获取SXSSFWorkbook实例
sxssfWorkbook = new SXSSFWorkbook();
// sheet名称
//Sheet sheet = sxssfWorkbook.createSheet(fileName);
//导出
for (int i = 0; i < sheetTile.length; i++) {
excelExport.exportExcelPoiTool(sxssfWorkbook, i, sheetTile[i], headers, fieldName, (List<HashMap<String, Object>>) list.get(i), type);
}
//在后面设置sheet
//setSheet(sheet);
//在这里不能写这一行,写上这一行后,导出的文件会有问题。
//fos = new FileOutputStream(excelExportDestfilepath);
sxssfWorkbook.write(fos);
fos.flush();//为压缩文件做准备
fileNameList.add(file);//为压缩文件做准备
long endTime = System.currentTimeMillis();
logger.info("数据全部导出至excel总耗时:{} 毫秒!", endTime - startTime, list.size());
} catch (Exception e) {
logger.error("发生异常咯!", e);
} finally {
try {
if (sxssfWorkbook != null)
// dispose of temporary files backing this workbook on disk -> 处
// 理SXSSFWorkbook导出excel时,产生的临时文件
sxssfWorkbook.dispose();
if (fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static String toZipFiles(final HttpServletRequest request, final List<String> fileNameList,
final String zipFileName) {
String zipFilePath = request.getRealPath(File.separator + "excel") + File.separator + zipFileName;
logger.info("begin to create zip file");
final File[] files = new File[fileNameList.size()];
for (int i = 0; i < fileNameList.size(); i++) {
files[i] = new File(fileNameList.get(i));
}
// 压缩文件
final File zipFile = new File(zipFilePath);
// 将excel文件压缩成zip文件
final byte[] buf = new byte[1024];
ZipOutputStream zipOut = null;
FileInputStream fis = null;
try {
zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
for (int i = 0; i < files.length; i++) {
fis = new FileInputStream(files[i]);
zipOut.putNextEntry(new ZipEntry(files[i].getName()));
int len = 0;
while ((len = fis.read(buf)) > 0) {
zipOut.write(buf, 0, len);
}
zipOut.closeEntry();
fis.close();
}
} catch (final Exception e) {
zipFilePath = null;
logger.error("failed to create zip file");
} finally {
if (zipOut != null) {
try {
zipOut.close();
} catch (final IOException e) {
logger.error("failed to close ZipOutputStream");
}
}
if (fis != null) {
try {
fis.close();
} catch (final IOException e) {
logger.error("failed to close FileInputStream");
}
}
}
return zipFilePath;
}
public static void downloadZip(final OutputStream out, final String zipFilePath) {
logger.info("begin to download zip file from " + zipFilePath);
FileInputStream inStream = null;
try {
inStream = new FileInputStream(zipFilePath);
final byte[] buf = new byte[4096];
int readLength;
while (((readLength = inStream.read(buf)) != -1)) {
out.write(buf, 0, readLength);
}
out.flush();
} catch (final Exception e) {
logger.error("download zip excel failed");
} finally {
try {
inStream.close();
} catch (final IOException e) {
logger.error("failed to close FileInputStream");
}
try {
out.close();
} catch (final IOException e) {
logger.error("failed to close OutputStream");
}
}
}
}
调用exportToExcelByPoi_zip方法
1、listQuarterExcel的格式:List<List<HashMap<String, Object>>
2、headers:表头
3、field:表头对应的字段名
4、fileName:文件名
5、sheetTitle:sheet名称
6、type:用来区分不同的页面的导出