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:用來區分不同的頁面的導出