import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.CollectionUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
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.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.pingan.qhcs.map.loan.pg.util.adapter.IQuery;
import net.sf.jxls.transformer.XLSTransformer;
/***
*
* @author
* @desc 通过jxls 工具 定制模板生产Excel报表
* @date 2017-09-12 13:53
*/
public class JxlsExcelUtils {
private static final Logger logger = LoggerFactory.getLogger(JxlsExcelUtils.class);
public static void loadFileToHttpServletResponse(String saveFile,HttpServletResponse response) {
File file = new File(saveFile);
ServletOutputStream ops = null;
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
response.setContentLength((int) file.length());
byte[] buffer = new byte[64 * 1024];
int count;
ops = response.getOutputStream();
while ((count = fis.read(buffer)) > 0)
ops.write(buffer, 0, count);
} catch (Exception e) {
e.printStackTrace();
}
finally {
try {
fis.close();
ops.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 将文件名中的汉字转为UTF8编码的串,以便下载时能正确显示另存的文件名
*
* @param s
* 原文件名
* @return 重新编码后的文件名
*/
public static String toUtf8String(String s) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c >= 0 && c <= 255) {
sb.append(c);
} else {
byte[] b;
try {
b = Character.toString(c).getBytes("utf-8");
} catch (Exception ex) {
ex.printStackTrace();
b = new byte[0];
}
for (int j = 0; j < b.length; j++) {
int k = b[j];
if (k < 0)
k += 256;
sb.append("%" + Integer.toHexString(k).toUpperCase());
}
}
}
return sb.toString();
}
/**
* @Description: 下载excel
* @author:
* @date: 2017/09/12 15:31:08
* @param path
* 模板路径
* @param destFileName
* 保存文件名称
* @param map
* 数据
* @param response
* @throws UnsupportedEncodingException
*/
public static void doDownload(String path, String destFileName,Map<String, Object> map, HttpServletResponse response) {
XLSTransformer transformer = new XLSTransformer();
InputStream in = null;
OutputStream out = null;
try {
//String fileName = URLEncoder.encode(destFileName, "utf-8");
//String fileName = new String((destFileName).getBytes("UTF-8"), "ISO-8859-1");
String fileName = destFileName ;
logger.info("destFileName:" + fileName);
response.reset();
response.setCharacterEncoding("UTF-8");
//这里对文件名进行编码,保证下载时汉字显示正常
//response.setContentType("application/vnd.ms-excel;charset=utf-8");
//Content-disposition属性设置成以附件方式进行下载
//response.setHeader("Content-Disposition", "attachment;filename="+ fileName);
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
in = new BufferedInputStream(new FileInputStream(path));
Workbook workbook = transformer.transformXLS(in, map);
out = response.getOutputStream();
workbook.write(out);
out.flush();
} catch (InvalidFormatException e) {
logger.error("doDownload-->InvalidFormatException:" + e);
} catch (IOException e) {
//e.printStackTrace();
logger.error("doDownload-->IOException:" + e);
}catch (Exception e) {
logger.error("doDownload-->Exception:" + e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
logger.error("doDownload-->in.close:" + e);
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
logger.error("doDownload-->out.close:" + e);
}
}
}
}
/**
* @Description: 下载excel
* @author:
* @date: 2017/09/12 15:31:08
* @param path
* 模板路径
* @param destFileName
* 保存文件名称
* @param map
* 数据
* @param response
* @throws UnsupportedEncodingException
*/
public static void doDownload(InputStream in, String destFileName,Map<String, Object> map, HttpServletResponse response) {
XLSTransformer transformer = new XLSTransformer();
//InputStream in = null;
OutputStream out = null;
try {
//String fileName = URLEncoder.encode(destFileName, "utf-8");
//String fileName = new String((destFileName).getBytes("UTF-8"), "ISO-8859-1");
String fileName = destFileName ;
logger.info("destFileName:" + fileName);
response.reset();
response.setCharacterEncoding("UTF-8");
//这里对文件名进行编码,保证下载时汉字显示正常
//response.setContentType("application/vnd.ms-excel;charset=utf-8");
//Content-disposition属性设置成以附件方式进行下载
//response.setHeader("Content-Disposition", "attachment;filename="+ fileName);
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
in = new BufferedInputStream(in);
Workbook workbook = transformer.transformXLS(in, map);
out = response.getOutputStream();
workbook.write(out);
out.flush();
} catch (InvalidFormatException e) {
logger.error("doDownload-->InvalidFormatException:" + e);
} catch (IOException e) {
logger.error("doDownload-->IOException:" + e);
}catch (Exception e) {
logger.error("doDownload-->Exception:" + e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
logger.error("doDownload-->in.close:" + e);
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
logger.error("doDownload-->out.close:" + e);
}
}
}
}
//-----------------------------------------------------------------------------------------
/****
数据库中存在大量的数据,我们要查询,怎么办?我们在没有经过设计的时候是这样来处理的,先写一个集合,然后执行jdbc,将返回的结果赋值给list,然后再返回到页面上,但是当数据量大的时候,就会出现数据无法返回,内存溢出的情况,于是我们在有限的时间和空间下,通过分页将数据一页一页的显示出来,这样可以避免了[大数据
量数据对内存的占用,也提高了用户的体验,在我们要导出的百万数据也是一个道理,内存突发性占用,我们可以限制导出数据所占用的内存,
这里我先建立一个list容器,list中开辟10000行的存储空间,每次存储10000行,用完了将内容清空,然后重复利用
,这样就可以有效控制内存,所以我们的设计思路就基本形成了,所以分页数据导出共有以下3个步骤:
1、求数据库中待导出数据的行数
2、根据行数求数据提取次数
3、按次数将数据写入文件
*/
/**
* @author LIUZILIANG856
* @desc 添加 2017-11-15 15:05
* @param response
* @param fileName
* @param sheetName
* @param listData
* @param columns
* @throws Exception
*/
public static void exportBigDataExcelByPageSize(HttpServletResponse response, String fileName, String sheetName,List<Map<String, Object>> listData, List<String> columns,IQuery<?,?> query) throws Exception {
exportBigDataExcelByPageSize(response, fileName, listData, sheetName, columns,query);
}
/**
* 下载excel
* @desc 添加 2017-11-15 15:05
* @param response
* @param filename 文件名 ,如:20150808.xls
* @param listData 数据源
* @param sheetName 表头名称
* @param columns 列名称集合,如:{姓名,性别,地址}
* @throws Exception
*/
private static void exportBigDataExcelByPageSize(HttpServletResponse response, String filename, List<Map<String, Object>> listData,
String sheetName, List<String> columns,IQuery<?,?> query) throws Exception {
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
exportBigDataExcelByPageSiz(response, listData, sheetName, columns,query);
}
/**
* @author
* @date 2017-11-09 20:49
* @desc 采用poi导出百万级别大数据
* @param objData 导出内容数组
* @param sheetName 导出工作表的名称
* @param columns 导出Excel的表头数组
* @return
*/
private static final int page_size = 100 ;// 数据库中存储的数据行数
@SuppressWarnings({ "rawtypes", "static-access" })
private static void exportBigDataExcelByPageSiz(HttpServletResponse response, List<Map<String, Object>> objData, String sheetName,
List<String> columns,IQuery<?,?> query) {
OutputStream os = null ;
SXSSFWorkbook wb = new SXSSFWorkbook(100); //最重要的就是使用SXSSFWorkbook,表示流的方式进行操作
wb.setCompressTempFiles(false);//临时文件进行压缩,建议不要true,否则会影响导出时间
Sheet sheet = wb.createSheet(sheetName); //工作表对象
Row nRow = sheet.createRow(0); // 创建第一行对象
Cell nCell = null ;
CellStyle cellStyle=wb.createCellStyle(); // 创建单元格样式
Font font = wb.createFont();
font.setFontHeightInPoints((short) 10);
font.setFontName("微软雅黑");
font.setItalic(true);
cellStyle.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
cellStyle.setFillForegroundColor((short)43);
cellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
cellStyle.setFont(font);
if (columns != null && columns.size() > 0) {
for (int j = 0; j < columns.size(); j++) {
nCell = nRow.createCell(j);
nCell.setCellStyle(cellStyle);
nCell.setCellValue(columns.get(j).split("_")[1]);//创建表头
}
}
long startTime = System.currentTimeMillis(); //开始时间
logger.info("strat execute time: " + startTime);
try {
os = response.getOutputStream();
//int page_size = 10000;// 数据库中存储的数据行数
PageHelper.startPage(1, 1);
List<Map> resultList = query.queryForList();
Page<Map> page = new Page<Map>() ;
int list_count = 0 ;
if (resultList != null) {
if(!resultList.isEmpty()) {
page = (Page<Map>) resultList ;
list_count = (int) page.getTotal();
}
}
int export_times = list_count % page_size > 0 ? list_count / page_size + 1 : list_count / page_size;
for (int j = 0; j < export_times; j++) {
PageHelper.startPage(j + 1,page_size);
resultList = query.queryForList();
if (resultList != null) {
if(!resultList.isEmpty()) {
page = (Page<Map>) resultList ;
}
}
int len = page.getResult().size() < page_size ? page.getResult().size() : page_size;
for (int i = 0; i < len; i++) {
nRow = sheet.createRow(j * page_size + i + 1);//新建行对象
Map map = page.getResult().get(i);
for (int k = 0; k < columns.size(); k++) {
nRow.createCell(k).setCellValue("null".equals(String.valueOf(map.get(columns.get(k).split("_")[0]))) ? null
:String.valueOf(map.get(columns.get(k).split("_")[0])));
}
}
resultList.clear();
}
wb.write(os);
os.close();
os.flush();//刷新缓冲区
wb.dispose();
long stopTime = System.currentTimeMillis(); //写文件时间
logger.info("write xlsx file time: " + (stopTime - startTime)/1000 + "m");
logger.info("exportToExcel successful!");
} catch (Exception e) {
logger.error("exportToExcel error: " + e.getMessage());
}
}
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
/**
* @author
* @desc 修改
* @param response
* @param fileName
* @param sheetName
* @param listData
* @param columns
* @throws Exception
*/
public static void exportBigDataExcel(HttpServletResponse response, String fileName, String sheetName,List<Map<String, Object>> listData, List<String> columns) throws Exception {
exportBigDataExcel(response, fileName, listData, sheetName, columns);
}
/**
* 下载excel
* @param response
* @param filename 文件名 ,如:20150808.xls
* @param listData 数据源
* @param sheetName 表头名称
* @param columns 列名称集合,如:{姓名,性别,地址}
* @throws Exception
*/
private static void exportBigDataExcel(HttpServletResponse response, String filename, List<Map<String, Object>> listData,
String sheetName, List<String> columns) throws Exception {
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
exportBigDataExcel(response, listData, sheetName, columns);
}
/**
* @author
* @date 2017-11-09 20:49
* @desc 采用poi导出百万级别大数据
* @param objData 导出内容数组
* @param sheetName 导出工作表的名称
* @param columns 导出Excel的表头数组
* @return
*/
private static final int sheetCount = 50000 ;
private static void exportBigDataExcel(HttpServletResponse response, List<Map<String, Object>> objData, String sheetName,
List<String> columns) {
OutputStream os = null ;
SXSSFWorkbook wb = null ;
try {
os = response.getOutputStream();
//在内存中保持100行,超过100行将被刷新到磁盘
wb = new SXSSFWorkbook(100); //最重要的就是使用SXSSFWorkbook,表示流的方式进行操作
wb.setCompressTempFiles(false);//临时文件进行压缩,建议不要true,否则会影响导出时间
Sheet sheet = null; //工作表对象
Row nRow = null; //行对象
Cell nCell = null ;
CellStyle cellStyle=wb.createCellStyle(); // 创建单元格样式
Font font = wb.createFont();
font.setFontHeightInPoints((short) 10);
font.setFontName("微软雅黑");
font.setItalic(true);
long startTime = System.currentTimeMillis(); //开始时间
logger.info("strat execute time: " + startTime);
int rowNo = 0; //总行号
int pageRowNo = 0; //页行号
if (CollectionUtils.isNotEmpty(objData)) {
for ( int i = 0 ;i < objData.size() ; i++ ) {
//打印300000条后切换到下个工作表,可根据需要自行拓展,2百万,3百万...数据一样操作,只要不超过1048576就可以
if( rowNo % sheetCount == 0 ){
logger.info("Current Sheet:" + rowNo / sheetCount);
sheet = wb.createSheet(sheetName + (rowNo / sheetCount));//建立新的sheet对象
sheet = wb.getSheetAt(rowNo / sheetCount); //动态指定当前的工作表
sheet.autoSizeColumn(1, true);//自适应列宽度
pageRowNo = 0; //每当新建了工作表就将当前工作表的行号重置为0
nRow = sheet.createRow(pageRowNo); // 创建第一行对象
cellStyle.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
cellStyle.setFillForegroundColor((short)43);
cellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
cellStyle.setFont(font);
if (columns != null && columns.size() > 0) {
for (int j = 0; j < columns.size(); j++) {
nCell = nRow.createCell(j);
nCell.setCellStyle(cellStyle);
nCell.setCellValue(columns.get(j));//创建表头
}
}
}
rowNo++;
nRow = sheet.createRow(++pageRowNo);//新建行对象
Map<String, Object> map = objData.get(i);
for (int j = 0; j < columns.size(); j++) {
nRow.createCell(j).setCellValue("null".equals(String.valueOf(map.get(columns.get(j)))) ? null
:String.valueOf(map.get(columns.get(j))));
}
if (rowNo % 10000 == 0) {
logger.info("row no: " + rowNo);
}
Thread.sleep(1);//休息一下,防止对CPU占用,其实影响不大
}
}
long finishedTime = System.currentTimeMillis(); //处理完成时间
logger.info("finished execute time: " + (finishedTime - startTime)/1000 + "m");
wb.write(os);
os.close();
os.flush();//刷新缓冲区
wb.dispose();
long stopTime = System.currentTimeMillis(); //写文件时间
logger.info("write xlsx file time: " + (stopTime - startTime)/1000 + "m");
logger.info("exportToExcel successful!");
} catch (Exception e) {
logger.error("exportToExcel error: " + e.getMessage());
}
}
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
/**
* @author
* @desc 添加
* 多sheet、按pageSize进行分页 多sheet写入
* @date 2017-11-17 13:37
* @param response
* @param fileName
* @param sheetName
* @param listData
* @param columns
* @throws Exception
*/
public static void exportBgDataExcelForSheetByPageSize(HttpServletResponse response, String fileName, String sheetName,
Map<String, Object> paramMaps, List<String> columns,IQuery<?,?> query) throws Exception {
exportBgDataExcelForSheetByPageSize(response, fileName, paramMaps, sheetName, columns,query);
}
/**
* 下载excel
* @param response
* @param filename 文件名 ,如:20150808.xls
* @param listData 数据源
* @param sheetName 表头名称
* @param columns 列名称集合,如:{姓名,性别,地址}
* @throws Exception
*/
private static void exportBgDataExcelForSheetByPageSize(HttpServletResponse response, String filename, Map<String, Object> paramMaps,
String sheetName, List<String> columns,IQuery<?,?> query) throws Exception {
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
exportBgDataExcelForSheetByPageSize(response, paramMaps, sheetName, columns,query);
}
/**
* @author
* @date 2017-11-17 14:41
* @desc 采用poi导出百万级别大数据(大数据量按pageSize分页查询然后在多sheet写入【因为单个sheet只能承受100万级别的数据量】)
* @param objData 导出内容数组
* @param sheetName 导出工作表的名称
* @param columns 导出Excel的表头数组
* @return
*/
private static final int sheetTotalCount = 500000;//单个sheet的数量
private static final int pageSize = 50000 ;// 数据库中存储的数据行数
@SuppressWarnings("unchecked")
private static void exportBgDataExcelForSheetByPageSize(HttpServletResponse response, Map<String, Object> paramMaps, String sheetName,
List<String> columns,IQuery<?,?> query) {
OutputStream os = null ;
SXSSFWorkbook wb = null ;
try {
os = response.getOutputStream();
wb = new SXSSFWorkbook(5000); //最重要的就是使用SXSSFWorkbook,表示流的方式进行操作
wb.setCompressTempFiles(false);//临时文件进行压缩,建议不要true,否则会影响导出时间
Sheet sheet = null; //工作表对象
Row nRow = null; // 创建第一行对象
Cell nCell = null ;
CellStyle cellStyle=wb.createCellStyle(); // 创建单元格样式
Font font = wb.createFont();
font.setFontHeightInPoints((short) 10);
font.setFontName("微软雅黑");
font.setItalic(true);
cellStyle.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
cellStyle.setFillForegroundColor((short)43);
cellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
cellStyle.setFont(font);
long startTime = System.currentTimeMillis(); //开始时间
logger.info("strat execute time: " + startTime);
PageHelper.startPage(1, 1);
List<Map> resultList = (List<Map>) query.queryForList();
Page<Map> page = new Page<Map>() ;
int list_count = 0 ;
if (resultList != null) {
if(!resultList.isEmpty()) {
page = (Page<Map>) resultList ;
list_count = (int) page.getTotal();//获取总记录数
}
}
int export_times = list_count % pageSize > 0 ? list_count / pageSize + 1 : list_count / pageSize;
int rowNo = 0; //总行号
int pageRowNo = 0; //页行号
for (int j = 0; j < export_times; j++) {
PageHelper.startPage( j + 1 , pageSize);
resultList = (List<Map>) query.queryForList();
if (resultList != null) {
if(!resultList.isEmpty()) {
page = (Page<Map>) resultList ;
}
}
List<Map> objData = page.getResult();
if (CollectionUtils.isNotEmpty(objData) && list_count > 0) {
for ( int i = 0 ;i < objData.size() ; i++ ) {
//打印100000条后切换到下个工作表,可根据需要自行拓展,2百万,3百万...数据一样操作,只要不超过1048576就可以
if( rowNo % sheetTotalCount == 0 ){
logger.info("Current Sheet:" + rowNo / sheetTotalCount);
sheet = wb.createSheet(sheetName + (rowNo / sheetTotalCount));//建立新的sheet对象
sheet = wb.getSheetAt(rowNo / sheetTotalCount); //动态指定当前的工作表
sheet.autoSizeColumn(1, true);//自适应列宽度
pageRowNo = 0; //每当新建了工作表就将当前工作表的行号重置为0
nRow = sheet.createRow(pageRowNo); // 创建第一行对象
cellStyle.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
cellStyle.setFillForegroundColor((short)43);
cellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
cellStyle.setFont(font);
if (columns != null && columns.size() > 0) {
for (int k = 0; k < columns.size(); k++) {
nCell = nRow.createCell(k);
nCell.setCellStyle(cellStyle);
nCell.setCellValue(columns.get(k).split("_")[1]);//创建表头
}
}
}
rowNo++;
nRow = sheet.createRow(++pageRowNo);//新建行对象
Map<String, Object> map = objData.get(i);
for (int e = 0; e < columns.size(); e++) {
nRow.createCell(e).setCellValue("null".equals(String.valueOf(map.get(columns.get(e).split("_")[0]))) ? null
:String.valueOf(map.get(columns.get(e).split("_")[0])));
}
if (rowNo % 10000 == 0) {
logger.info("row no: " + rowNo);
}
Thread.sleep(1);//休息一下,防止对CPU占用,其实影响不大
}//rowNo end
}
resultList.clear();
}
wb.write(os);
os.close();
os.flush();//刷新缓冲区
wb.dispose();
long stopTime = System.currentTimeMillis(); //写文件时间
logger.info("write xlsx file time: " + (stopTime - startTime)/1000 + "m");
logger.info("exportToExcel successful!");
} catch (Exception e) {
logger.error("exportBgDataExcelForSheetByPageSize error: " + e);
}
}
//-----------------------------------------------------------------------------------------
}