由于数据量过大时,生成Excel速度很慢,过程中内存占用量很大。因此当数据条数大于10000时,不支持生成Excel文件,并且使用CopyManager(postgresql中的工具)来生成CSV文件。

利用查询后的结果生成Excel和CSV文件的代码。

import com.unicom.simpledemo.dao.UserDefinedSQLMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
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.postgresql.copy.CopyManager;
import org.postgresql.core.BaseConnection;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.*;

/**
 * Author by BayMin, Date on 2018/11/15.
 */
@Slf4j
@Component
public class ExportUtils {
    private static String driverClass;
    private static String dbUrl;
    private static String dbUserName;
    private static String dbPassword;

    @Value("${spring.datasource.druid.driver-class-name}")
    public void setDriverClass(String str) {
        driverClass = str;
    }

    @Value("${spring.datasource.druid.url}")
    public void setDbUrl(String str) {
        dbUrl = str;
    }

    @Value("${spring.datasource.druid.username}")
    public void setDbUserName(String str) {
        dbUserName = str;
    }

    @Value("${spring.datasource.druid.password}")
    public void setDbPassword(String str) {
        dbPassword = str;
    }

    /**
     * 根据查询结果生成Excel
     *
     * @return 生成的Excel
     */
    @SuppressWarnings("unchecked")
    public static SXSSFWorkbook mapListToExcel(HttpSession session, UserDefinedSQLMapper userDefinedSQLMapper) {
        List<LinkedHashMap<String, Object>> linkedHashMaps = null;
        int rows = (int) session.getAttribute("rows");
        if (rows >= 10000) {
            log.error("行数为" + rows + ",不小于10000行,无法导出为Excel表格!");
            return null;
        }
        linkedHashMaps = (List<LinkedHashMap<String, Object>>) session.getAttribute("linkedHashMaps");
        log.info("正在生成Excel表格...");
        SXSSFWorkbook workbook = new SXSSFWorkbook(100);
        SXSSFSheet sheet = workbook.createSheet("result");
        SXSSFRow row = sheet.createRow(0);
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        LinkedList<String> keys = (LinkedList<String>) session.getAttribute("keys");
        int columnNum = keys.size();
        for (int i = 0; i < columnNum; i++) {
            SXSSFCell cell = row.createCell(i);
            cell.setCellValue(keys.get(i));
            cell.setCellStyle(style);
            sheet.trackAllColumnsForAutoSizing();
            sheet.autoSizeColumn(i);
        }
        for (int i = 0; i < linkedHashMaps.size(); i++) {
            row = sheet.createRow(i + 1);
            if (linkedHashMaps.get(i) != null) {
                Iterator<Map.Entry<String, Object>> iterator = linkedHashMaps.get(i).entrySet().iterator();
                int j = 0;
                while (iterator.hasNext()) {
                    Map.Entry<String, Object> next = iterator.next();
                    if (next.getValue() != null) {
                        row.createCell(j++).setCellValue(next.getValue().toString());
                    } else {
                        row.createCell(j++).setCellValue("");
                    }
                }
            } else {
                row.createCell(0).setCellValue("");
            }
        }
        log.info("生成Excel表格完成!");
        return workbook;
    }


    /**
     * 导出Excel
     *
     * @param workbook 需要导出的Excel
     */
    public static void exportExcel(HttpServletRequest request, HttpServletResponse response, SXSSFWorkbook workbook) {
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-disposition", "attachment;filename=Table-" + Utils.parseDate(new Date()) + ".xlsx");
        try {
            OutputStream outputStream = response.getOutputStream();
            workbook.write(outputStream);
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 导出CSV文件
     *
     * @param session session(其中包含sql)
     */
    @SuppressWarnings("unchecked")
    public static void exportCSV(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
        LinkedList<String> keys = (LinkedList<String>) session.getAttribute("keys");
        StringBuilder tableHead = new StringBuilder();
        for (String str : keys) {
            tableHead.append(str).append(",");
        }
        String headString = tableHead.substring(0, tableHead.length() - 1);
        headString = headString.concat("\n");
        try {
            response.setContentType("text/csv");
            response.setHeader("Content-disposition", "attachment;filename=Table-" + Utils.parseDate(new Date()) + ".csv");
            OutputStream outputStream = response.getOutputStream();
            if ((int) session.getAttribute("rows") >= 10000) {
                exportCSVBySQL(request, response, session, headString, outputStream);
            } else {
                exportCSVBySession(request, response, session, headString, outputStream);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @SuppressWarnings("unchecked")
    private static void exportCSVBySession(HttpServletRequest request, HttpServletResponse
            response, HttpSession session, String headString, OutputStream outputStream) {
        StringBuilder stringBuilder = new StringBuilder(headString);
        String csv = "";
        List<LinkedHashMap<String, Object>> linkedHashMapsTop500 = (List<LinkedHashMap<String, Object>>) session.getAttribute("linkedHashMaps");
        for (LinkedHashMap<String, Object> linkedHashMap : linkedHashMapsTop500) {
            for (Map.Entry<String, Object> next : linkedHashMap.entrySet()) {
                if (next.getValue() != null) {
                    stringBuilder.append(next.getValue().toString());
                }
                stringBuilder.append(",");
            }
            stringBuilder.deleteCharAt(stringBuilder.length() - 1).append("\n");
        }
        csv = stringBuilder.substring(0, stringBuilder.length() - 1);
        outputStreamWrite(csv, outputStream);
        try {
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void exportCSVBySQL(HttpServletRequest request, HttpServletResponse response, HttpSession
            session, String headString, OutputStream outputStream) {
        outputStreamWrite(headString, outputStream);
        String sql = session.getAttribute("sql").toString();
        try {
            Class.forName(driverClass);
            Connection connection = DriverManager.getConnection(dbUrl, dbUserName, dbPassword);
            CopyManager copyManager = new CopyManager((BaseConnection) connection);
            copyManager.copyOut("copy (" + sql + ") to stdout with csv", outputStream);
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            log.error("使用COPY命令导出CSV文件出错,当前SQL为:" + sql);
            e.printStackTrace();
        }
    }

    private static void outputStreamWrite(String info, OutputStream outputStream) {
        byte[] bytes = info.getBytes();
        InputStream inputStream = new ByteArrayInputStream(bytes);
        byte[] buff = new byte[1024];
        int len;
        try {
            while ((len = inputStream.read(buff)) != -1) {
                outputStream.write(buff, 0, len);
                outputStream.flush();
            }
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


时至今日,你依旧是我的光芒。