Java使用POI实现百万级数据导出

一、思路

Java使用POI导出Excel,采用2万一个Excel,生成后放到服务器某路径文件夹下,循环查询并生成直到数据全部导出到Excel后,打包成Zip压缩包并循环删除已被打包的Excel,打包完成后弹窗下载。

目前的效率如下:

1591550 15分钟

999650   8分钟

909030   2分钟

833150  1分钟

139840   1分钟

粗略时间,未精确计算。

二、实现代码

controller层

/**
     * <p>
     * Title: OneclickExport
     * </p>
     * <p>
     * Description:一键导出所有操作日志
     * </p>
     * 
     * @author Saffichan
     * @param response
     * @throws Exception
     * @throws UnsupportedEncodingException
     * @throws LogNotFoundException
     */
    @RequestMapping("/oneclickExport")
    public ModelAndView oneclickExport(LogBO logBO, HttpServletResponse response, HttpSession session,
            HttpServletRequest request) throws Exception {

        List<Map<String, Object>> dataList = null;

        LogBO logs = null;
        if (session.getAttribute("logBO") == null || session.getAttribute("logBO").equals("")) {
            logs = new LogBO();
        } else {
            logs = (LogBO) session.getAttribute("logBO");

        }
        int counts = logService.count(logs);

        int page = 1;
        int pageSize = 20000;
        int count = (counts+pageSize-1)/pageSize;

        if (count > 1) {
            for (int i = 0; i <= count; i++) {
                logs.setCurrentPage(page);
                logs.setPageOfSize(pageSize);
                List<LogBO> logBOs = logService.selectAll(logs);
                if (logBOs != null) {
                    // 对象转为List<Map>
                    dataList = getDataListMethods(logBOs);
                    exportAll(dataList, page, request);
                    page = page + 1;

                }

            }
            // 生成文件名
            String fileName = "OperationLog"+ new SimpleDateFormat("yyyyMMDDhh24mmssSSS").format(System.currentTimeMillis());

            ZipFileAction zip = new ZipFileAction();
            zip.downloadZip(fileName, response, request);
        } else {
            logs.setCurrentPage(page);
            logs.setPageOfSize(pageSize);
            List<LogBO> logBOs = logService.selectAll(logs);
            if (logBOs != null) {
                // 对象转为List<Map>
                dataList = getDataListMethods(logBOs);
                export(dataList, response);
            } else if (logBOs == null) {
                return null;
            }

        }

        return null;
    }
//导出全部
public void exportAll(List<Map<String, Object>> dataList, int page, HttpServletRequest request) {
        // 栏目
        String[] columnName = { getI18n("Log.logUsername"), getI18n("Log.logModule"), getI18n("Log.logMethods"),
                getI18n("Log.logActionurl"), getI18n("Log.logIP"), getI18n("Log.logDate"), getI18n("Log.logCommite") };
        // 取值
        String[] valueName = { "username", "module", "methods", "actionurl", "ip", "date", "commite" };

        // 生成文件名
        String fileName = "OperationLog" +page+ new SimpleDateFormat("yyyyMMDDhh24mmssSSS").format(System.currentTimeMillis());
        try {
            OneCilckUtil.oneClickExportExcel(fileName, columnName, valueName, dataList, request);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
//导出单个Excel
public void export(List<Map<String, Object>> dataList, HttpServletResponse response) {
        // 栏目
        String[] columnName = { getI18n("Log.logUsername"), getI18n("Log.logModule"), getI18n("Log.logMethods"),
                getI18n("Log.logActionurl"), getI18n("Log.logIP"), getI18n("Log.logDate"), getI18n("Log.logCommite") };
        // 取值
        String[] valueName = { "username", "module", "methods", "actionurl", "ip", "date", "commite" };
        // 生成文件名
        String fileName = "OperationLog"+ new SimpleDateFormat("yyyyMMDDhh24mmssSSS").format(System.currentTimeMillis());
        try {
            ExportUtil.exportToExcel(fileName, columnName, valueName, dataList, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

调用接口

ZipFileAction.java

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ZipFileAction {
    
    //下载最终压缩包
    public int downloadZip(String fileName, HttpServletResponse response, HttpServletRequest request) throws Exception {
        // 原文件地址
        String sourceFilePath = request.getSession().getServletContext().getRealPath("") + "/ExcelFile";
        // 生成Zip压缩包存放路径
        String zipFilePath = request.getSession().getServletContext().getRealPath("") + "/download";
        // 生成文件名
        //String sourceFilePath = "D:\ExcelFile\";
        // String zipFilePath = "D:\download\";
        try {
            // 调用FileToZip接口生成压缩包
            boolean flag = FileToZip.fileToZip(sourceFilePath, zipFilePath, fileName);
            if (flag) {
                System.out.println("文件打包成功!");
            } else {
                System.out.println("文件打包失败!");
            }
            // Zip压缩包文件名
            String fileNames = fileName + ".zip";
            // Zip压缩包路径
            String path = request.getSession().getServletContext().getRealPath("") + "/download/" + fileNames;
            //String path = "D:\download\"+fileNames;
            File file = new File(path);
            if (file.length() < 1 || file == null) {
                return 1;

            } else {
                response.setCharacterEncoding("UTF-8");
                response.setHeader("Content-Disposition",
                        "attachment; filename=" + new String(fileNames.getBytes("ISO8859-1"), "UTF-8"));
                response.setContentLength((int) file.length());
                response.setContentType("application/zip");// 定义输出类型
                FileInputStream fis = new FileInputStream(file);

                BufferedInputStream buff = new BufferedInputStream(fis);
                byte[] b = new byte[1024];// 相当于我们的缓存
                long k = 0;// 该值用于计算当前实际下载了多少字节
                OutputStream myout = response.getOutputStream();// 从response对象中得到输出流,准备下载
                // 开始循环下载
                while (k < file.length()) {
                    int j = buff.read(b, 0, 1024);
                    k += j;
                    myout.write(b, 0, j);
                }
                // 刷新此输出流并强制将所有缓冲的输出字节被写出
                myout.flush();
                // 关闭流
                myout.close();
                buff.close();
                fis.close();
                // 删除生成的压缩包文件
                file.delete();

                // 删除项目文件夹下所有的文件
                File filedel = new File(sourceFilePath);
                if (filedel.isDirectory()) { // 如果path表示的是一个目录

                    File[] fileList = filedel.listFiles();
                    for (int i = 0; i < fileList.length; i++) {
                        File delfile = fileList[i];
                        if (!delfile.isDirectory()) { // 如果文件的不是一个目录,则删除
                            // 删除文件
                            delfile.delete();
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    
}

OneCilckUtil.java

import java.io.File;
import java.io.FileOutputStream;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFFont;

public class OneCilckUtil {

    /**
     * Excel导出公共模板
     * 
     * @param fileName
     * @param columnName
     *            [ID,名称,类型...]
     * @param valueName
     *            [id,name,type...]
     * @param dataList
     *            参数
     * @param response
     * @throws Exception
     */
    @SuppressWarnings("deprecation")
    public static void oneClickExportExcel(String fileName, String[] columnName, String[] valueName,
            List<Map<String, Object>> dataList, HttpServletRequest request) throws Exception {
        if (dataList.size() == 0) {
            return;
        }
        // 第一步,创建一个webbook,对应一个Excel文件
        SXSSFWorkbook wb = new SXSSFWorkbook(1000);
        // 第二步,在webbook中添加一个sheet,对应Excel文件中的sheet
        SXSSFSheet sheet = wb.createSheet(fileName);
        sheet.setDefaultColumnWidth(15); // 统一设置列宽

        // 创建第1行 也就是表头
        SXSSFRow row = sheet.createRow(0);

        // 第四步,创建表头单元格样式 以及表头的字体样式
        XSSFCellStyle style = (XSSFCellStyle) wb.createCellStyle();
        style.setWrapText(true);// 设置自动换行
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 创建一个居中格式
        style.setFillForegroundColor(HSSFColor.GREY_40_PERCENT.index);
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);

        style.setBottomBorderColor(HSSFColor.BLACK.index);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);

        XSSFFont headerFont = (XSSFFont) wb.createFont(); // 创建字体样式
        headerFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); // 字体加粗
        headerFont.setFontHeightInPoints((short) 12); // 设置字体大小
        style.setFont(headerFont); // 为标题样式设置字体样式

        XSSFCellStyle cellStyle = (XSSFCellStyle) wb.createCellStyle();
        cellStyle.setWrapText(true);// 设置自动换行
        cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 创建一个居中格式

        // 设置边框
        cellStyle.setBottomBorderColor(HSSFColor.BLACK.index);
        cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
        cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);

        // 为数据内容设置特点新单元格样式2 自动换行 上下居中左右也居中
        XSSFCellStyle hssfCellStyle = (XSSFCellStyle) wb.createCellStyle();
        hssfCellStyle.setWrapText(true);// 设置自动换行
        hssfCellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 创建一个上下居中格式
        hssfCellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 左右居中

        // 设置边框
        hssfCellStyle.setBottomBorderColor(HSSFColor.BLACK.index);
        hssfCellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        hssfCellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        hssfCellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
        hssfCellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
        // 第四.一步,创建表头的列
        for (int i = 0; i < columnName.length; i++) {
            SXSSFCell cell = row.createCell(i);
            cell.setCellValue(columnName[i]);
            cell.setCellStyle(style);
        }

        
        // 第五步,创建单元格,并设置值
        for (int i = 0; i < dataList.size(); i++) {
            row = sheet.createRow((int) i + 1);
            // 为数据内容设置特点新单元格样式1 自动换行 上下居中

            SXSSFCell datacell = null;

            Map<String, Object> map = dataList.get(i);
            for (int j = 0; j < valueName.length; j++) {
                datacell = row.createCell(j);
                datacell.setCellValue(String.valueOf(map.get((String) valueName[j])).equals("null") ? ""
                        : String.valueOf(map.get((String) valueName[j])));
                datacell.setCellStyle(hssfCellStyle);
            }
            map.clear();
        }
        dataList.clear();
        dataList = null;
        // 第六步,将文件存到浏览器设置的下载位置
        String filename = fileName + ".xlsx";
        String path = request.getSession().getServletContext().getRealPath("") + "/ExcelFile/" + filename;
        //String path = "D:\ExcelFile\" + filename;

        File file = new File(path);
        file.setReadOnly();
        FileOutputStream os = null;
        if (file.exists()) {
            System.out.println(path + "目录下存在名字为:" + filename + "的文件.");
        } else {
            try {
                os = new FileOutputStream(file);
                wb.write(os);// 将数据写出去

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 刷新此输出流并强制将所有缓冲的输出字节被写出
                os.flush();
                // 关闭流
                os.close();
                /*
                 * dispose of temporary files backing this workbook on disk 处理在磁盘上备份此工作簿的临时文件
                 * SXSSF分配临时文件,您必须始终清除显式,通过调用dispose方法
                 */
                wb.dispose();
                wb.close();
                System.gc();
            }
        }
    }
}

FileToZip.java

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author Saffi 将文件夹下面的文件 打包成zip压缩文件
 * @author Saffi
 * @date 2017-10-16
 */
public final class FileToZip {

    /**
     * 将存放在sourceFilePath目录下的源文件,打包成fileName名称的zip文件,并存放到zipFilePath路径下
     * 
     * @param sourceFilePath
     *            :待压缩的文件路径
     * @param zipFilePath
     *            :压缩后存放路径
     * @param fileName
     *            :压缩后文件的名称
     * @return
     * @throws IOException
     */
    public static boolean fileToZip(String sourceFilePath, String zipFilePath, String fileName) throws IOException {
        boolean flag = false;
        File sourceFile = new File(sourceFilePath);
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        FileOutputStream fos = null;
        ZipOutputStream zos = null;

        if (sourceFile.exists() == false) {
            System.out.println("待压缩的文件目录:" + sourceFilePath + "不存在.");
        } else {
            try {
                File zipFile = new File(zipFilePath + "/" + fileName + ".zip");
                if (zipFile.exists()) {

                    System.out.println(zipFilePath + "目录下存在名字为:" + fileName + ".zip" + "打包文件.");
                } else {
                    File[] sourceFiles = sourceFile.listFiles();
                    if (null == sourceFiles || sourceFiles.length < 1) {
                        System.out.println("待压缩的文件目录:" + sourceFilePath + "里面不存在文件,无需压缩.");
                    } else {

                        fos = new FileOutputStream(zipFile);
                        zos = new ZipOutputStream(new BufferedOutputStream(fos));
                        byte[] bufs = new byte[1024 * 10];
                        for (int i = 0; i < sourceFiles.length; i++) {
                            // 创建ZIP实体,并添加进压缩包
                            ZipEntry zipEntry = new ZipEntry(sourceFiles[i].getName());
                            zos.putNextEntry(zipEntry);

                            // 读取待压缩的文件并写进压缩包里
                            fis = new FileInputStream(sourceFiles[i]);
                            bis = new BufferedInputStream(fis, 1024 * 10);
                            int read = 0;
                            while ((read = bis.read(bufs, 0, 1024 * 10)) != -1) {
                                zos.write(bufs, 0, read);
                            }
                            if (null != bis) {
                                bis.close();
                            }
                        }
                        flag = true;
                        if (null != zos) {
                            zos.closeEntry();
                            zos.close();
                        }
                    }
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            } finally {
                // 关闭流
                try {
                    if (null != fis) {
                        fis.close();
                    }
                    if (null != fos) {
                        fos.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
            }
        }

        return flag;
    }

}

ExportUtil.java

/**
 * 导出工具类
 * @author Saffi
 *
 */
public class ExportUtil {

    /**
     * Excel导出公共模板
     * @param fileName
     * @param columnName [ID,名称,类型...]
     * @param valueName [id,name,type...]
     * @param dataList 参数
     * @param response
     * @throws Exception
     */
    @SuppressWarnings("deprecation")
    public static void exportToExcel(String fileName, String[] columnName, String[] valueName, List<Map<String, Object>> dataList, HttpServletResponse response) throws Exception {
        if (dataList.size() == 0) {
            return;
        }
        
        // 第一步,创建一个webbook,对应一个Excel文件
        SXSSFWorkbook wb = new SXSSFWorkbook(1000);
        // 第二步,在webbook中添加一个sheet,对应Excel文件中的sheet
        SXSSFSheet sheet = wb.createSheet(fileName);
        sheet.setDefaultColumnWidth(15); //统一设置列宽
        
        // 创建第1行 也就是表头
        SXSSFRow row = sheet.createRow(0);
        
        // 第四步,创建表头单元格样式 以及表头的字体样式
        XSSFCellStyle style = (XSSFCellStyle) wb.createCellStyle();
        style.setWrapText(true);// 设置自动换行
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 创建一个居中格式
        style.setFillForegroundColor(HSSFColor.GREY_40_PERCENT.index);
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        
        style.setBottomBorderColor(HSSFColor.BLACK.index);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        
        XSSFFont headerFont = (XSSFFont) wb.createFont(); // 创建字体样式
        headerFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); // 字体加粗
        headerFont.setFontHeightInPoints((short) 12); // 设置字体大小
        style.setFont(headerFont); // 为标题样式设置字体样式

        XSSFCellStyle cellStyle = (XSSFCellStyle) wb.createCellStyle();
        cellStyle.setWrapText(true);// 设置自动换行
        cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 创建一个居中格式

        // 设置边框
        cellStyle.setBottomBorderColor(HSSFColor.BLACK.index);
        cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
        cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);

        // 为数据内容设置特点新单元格样式2 自动换行 上下居中左右也居中
        XSSFCellStyle hssfCellStyle = (XSSFCellStyle) wb.createCellStyle();
        hssfCellStyle.setWrapText(true);// 设置自动换行
        hssfCellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 创建一个上下居中格式
        hssfCellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 左右居中

        // 设置边框
        hssfCellStyle.setBottomBorderColor(HSSFColor.BLACK.index);
        hssfCellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        hssfCellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        hssfCellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
        hssfCellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
        // 第四.一步,创建表头的列
        for (int i = 0; i < columnName.length; i++) {
            SXSSFCell cell = row.createCell(i);
            cell.setCellValue(columnName[i]);
            cell.setCellStyle(style);
        }

        // 第五步,创建单元格,并设置值
        for (int i = 0; i < dataList.size(); i++) {
            row = sheet.createRow((int) i + 1);
            // 为数据内容设置特点新单元格样式1 自动换行 上下居中
            
            SXSSFCell datacell = null;
            
            Map<String, Object> map = dataList.get(i);
            for (int j = 0; j < valueName.length; j++) {
                datacell = row.createCell(j);
                datacell.setCellValue(String.valueOf(map.get((String) valueName[j])).equals("null") ? "" : String.valueOf(map.get((String) valueName[j])));
                datacell.setCellStyle(hssfCellStyle);
            }
            map.clear();    
        }
        dataList.clear();
        dataList=null;
        // 第六步,将文件存到浏览器设置的下载位置
        String filename = fileName + ".xlsx";
        response.setContentType("application/ms-excel;charset=UTF-8");
        response.setHeader("Content-Disposition",
                "attachment;filename=".concat(String.valueOf(URLEncoder.encode(filename, "UTF-8"))));
        OutputStream out = response.getOutputStream();
        try {
            wb.write(out);// 将数据写出去
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 刷新此输出流并强制将所有缓冲的输出字节被写出
            out.flush();
            // 关闭流
            out.close();
            /*
             * dispose of temporary files backing this workbook on disk 处理在磁盘上备份此工作簿的临时文件
             * SXSSF分配临时文件,您必须始终清除显式,通过调用dispose方法
             */
            wb.dispose();
            wb.close();
            System.gc();
        }
    }
    
    @SuppressWarnings("deprecation")
    public static void exportToExcel(String fileName, String[] columnName, List<Object[]> dataList, HttpServletResponse response) throws Exception {
        if (dataList == null || dataList.size() == 0) {
            return;
        }
        // 第一步,创建一个webbook,对应一个Excel文件
        SXSSFWorkbook wb = new SXSSFWorkbook(1000);
        // 第二步,在webbook中添加一个sheet,对应Excel文件中的sheet
        SXSSFSheet sheet = wb.createSheet(fileName);
        sheet.setDefaultColumnWidth(15); //统一设置列宽
        
        // 创建第1行 也就是表头
        SXSSFRow row = sheet.createRow(0);
        
        // 第四步,创建表头单元格样式 以及表头的字体样式
        XSSFCellStyle style = (XSSFCellStyle) wb.createCellStyle();
        style.setWrapText(true);// 设置自动换行
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 创建一个居中格式
        style.setFillForegroundColor(HSSFColor.GREY_40_PERCENT.index);
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        
        style.setBottomBorderColor(HSSFColor.BLACK.index);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        
        XSSFFont headerFont = (XSSFFont) wb.createFont(); // 创建字体样式
        headerFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); // 字体加粗
        headerFont.setFontHeightInPoints((short) 12); // 设置字体大小
        style.setFont(headerFont); // 为标题样式设置字体样式

        // 第四.一步,创建表头的列
        for (int i = 0; i < columnName.length; i++) {
            SXSSFCell cell = row.createCell(i);
            cell.setCellValue(columnName[i]);
            cell.setCellStyle(style);
        }

        // 第五步,创建单元格,并设置值
        for (int i = 0; i < dataList.size(); i++) {
            row = sheet.createRow((int) i + 1);
            // 为数据内容设置特点新单元格样式1 自动换行 上下居中
            XSSFCellStyle cellStyle = (XSSFCellStyle) wb.createCellStyle();
            cellStyle.setWrapText(true);// 设置自动换行
            cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 创建一个居中格式

            // 设置边框
            cellStyle.setBottomBorderColor(HSSFColor.BLACK.index);
            cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
            cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
            cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
            cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);

            // 为数据内容设置特点新单元格样式2 自动换行 上下居中左右也居中
            XSSFCellStyle hssfCellStyle = (XSSFCellStyle) wb.createCellStyle();
            hssfCellStyle.setWrapText(true);// 设置自动换行
            hssfCellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 创建一个上下居中格式
            hssfCellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 左右居中

            // 设置边框
            hssfCellStyle.setBottomBorderColor(HSSFColor.BLACK.index);
            hssfCellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
            hssfCellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
            hssfCellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
            hssfCellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
            SXSSFCell datacell = null;
            Object[] map = dataList.get(i);
            for (int j = 0; j < columnName.length; j++) {
                datacell = row.createCell(j);
                datacell.setCellValue(String.valueOf(map[j]));
                datacell.setCellStyle(hssfCellStyle);
            }
            map=null;
        }
        dataList.clear();
        dataList=null;
        // 第六步,将文件存到浏览器设置的下载位置
        String filename = fileName + ".xlsx";
        response.setContentType("application/ms-excel;charset=UTF-8");
        response.setHeader("Content-Disposition",
                "attachment;filename=".concat(String.valueOf(URLEncoder.encode(filename, "UTF-8"))));
        OutputStream out = response.getOutputStream();
        try {
            wb.write(out);// 将数据写出去
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 刷新此输出流并强制将所有缓冲的输出字节被写出
            out.flush();
            // 关闭流
            out.close();
            /*
             * dispose of temporary files backing this workbook on disk 处理在磁盘上备份此工作簿的临时文件
             * SXSSF分配临时文件,您必须始终清除显式,通过调用dispose方法
             */
            wb.dispose();
            wb.close();
            System.gc();
        }
    }
}

因项目使用了Nginx进行反向代理,因此Nginx配置文件也需要设置,以免Nginx网关超时。

   #keepalive_timeout  0;
    keepalive_timeout  65;
    
    fastcgi_connect_timeout 200000s;
    fastcgi_send_timeout 200000s;
    fastcgi_read_timeout 200000s;

    #gzip  on;

    server {
        listen       80;
        server_name  域名 服务器IP;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;

        location / {
        proxy_pass http://localhost:端口;
        proxy_set_header   Host    $host;
        proxy_set_header   Remote_Addr    $remote_addr;
        proxy_set_header   X-Real-IP    $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_connect_timeout 200000s;
        proxy_send_timeout 200000s;
        proxy_read_timeout 200000s;
        }
原文地址:https://www.cnblogs.com/shoose/p/10445408.html