POI分sheet导出Excel或者zip通用高速方法(万条数据以上)

工作需要写了一个POI的封装类,接受的数据类型是List

 <settings>
        <!-- 当返回值为LinkedHashMap时,表中存储的null值并不会存入Map中,因此还要在mybatis配置 -->
        <setting name="callSettersOnNulls" value="true"/>
    </settings>

xml中写法
接受的数据类型是List<HashMap<String,Object>>,查询的字段顺序决定了列排列的顺序,如果不传入列名,使用List<HashMap<String,Object>>去取得列名,然后生成,

 <select id="getexceldata" resultType="java.util.LinkedHashMap">
      SELECT 
       ReportMonth, ExpenseNumber, Type, TotalActualExpenseAmount, RequesterNameCN, 
       RequesterEmployeeCode, Dept, Area, DeptConfirm, AreaConfirm, StartDate, EndDate, 
       ApprovalDate, AmountMonth, ApprovalNameCN, AccountantDate, AccountantDecision, AccountantNameCN, 
       InvoinceDate, Comments1, SysCreateDate, SysUpdateDate, OriginalId, BigBU
       FROM t_ermonthlyreport
  </select>
/**
 * POI导出方法类
 */
public class POIExcelExport {

    /**
     * 写入数据通用方法(导出多个sheet)
     * @param workbook
     * @param out        : OutputStream对象
     * @param limitNum   : 超过limitNum生成新sheet
     * @param sheetTitle : 设置excel的sheet标题
     * @param headers    : 设置excel的列标题
     * @param columnsize : 设置excel的列宽度
     * @param data       : List<HashMap<String,Object>> 数据
     * @throws IOException
     */
    public void setExcelData(HSSFWorkbook workbook,OutputStream out,int limitNum,String sheetTitle,
            String[] headers,int [] columnsize,List<LinkedHashMap<String,Object>> data) throws IOException{
        int sheetNum = 0;
        HSSFSheet sheet =null;
        HSSFRow row = null; 
        //设置标题样式和单元格样式 
        HSSFCellStyle titlestyle = createTitleCellStyle(workbook);
        HSSFCellStyle bodystyle = createBodyCellStyle(workbook);
        int length = columnsize.length;
        //遍历集合数据,产生数据行
        if(data!=null){
        int rowindex = 0;
            for(HashMap<String,Object> entry:data){
                if (rowindex % limitNum == 0){  
                    if(rowindex != 0 ){
                        sheetNum++;
                    }
                    sheet = workbook.createSheet(sheetTitle+sheetNum);
                    //设置sheet的列宽
                    for(int i=0;i<length;i++){
                        sheet.setColumnWidth(i, (short)columnsize[i]*256);
                    }
                    row = sheet.createRow(0);
                    createHeaders(headers,titlestyle,row);
                    rowindex = 1;
                }
                row = sheet.createRow(rowindex);
                int cellIndex = 0;
                 for (String key : headers){
                     HSSFCell cell = row.createCell(cellIndex);
                        cell.setCellStyle(bodystyle);
                        Object str = entry.get(key);
                        //处理空数据
                        if(str!=null ){
                            cell.setCellValue(str.toString());
                        }else{
                            cell.setCellValue(" ");
                        }
                        cellIndex++;
                   }
                rowindex++;
            }
        }
    }


    /**
     * 写入数据通用方法(导出多个sheet)重载
     * headers 自己从HashMap中取
     * @param workbook
     * @param out        : OutputStream对象
     * @param limitNum   : 超过limitNum生成新sheet
     * @param sheetTitle : 设置excel的sheet标题
     * @param columnsize : 设置excel的列宽度
     * @param data       : List<HashMap<String,Object>> 数据
     * @throws IOException
     */
    public void setExcelData(HSSFWorkbook workbook,OutputStream out,int limitNum,String sheetTitle,
            int [] columnsize,List<LinkedHashMap<String,Object>> data) throws IOException{
        int sheetNum = 0;
        HSSFSheet sheet =null;
        HSSFRow row = null; 
        //设置标题样式和单元格样式 
        HSSFCellStyle titlestyle = createTitleCellStyle(workbook);
        HSSFCellStyle bodystyle = createBodyCellStyle(workbook);
        int length = columnsize.length;
        String [] headers = null;
        //遍历集合数据,产生数据行
        if(data!=null){
        int rowindex = 0;
            for(HashMap<String,Object> entry:data){
                if (rowindex % limitNum == 0){  
                    if(rowindex != 0 ){
                        sheetNum++;
                    }
                    sheet = workbook.createSheet(sheetTitle+sheetNum);
                    //设置sheet的列宽
                    for(int i=0;i<length;i++){
                        sheet.setColumnWidth(i, (short)columnsize[i]*256);
                    }
                    row = sheet.createRow(0);
                    headers  =createHeaders(data,titlestyle,row);
                    rowindex = 1;
                }
                row = sheet.createRow(rowindex);
                int cellIndex = 0;
                 for (String key : headers){
                     HSSFCell cell = row.createCell(cellIndex);
                        cell.setCellStyle(bodystyle);
                        Object str = entry.get(key);
                        //处理空数据
                        if(str!=null ){
                            cell.setCellValue(str.toString());
                        }else{
                            cell.setCellValue(" ");
                        }
                        cellIndex++;
                   }
                rowindex++;
            }
        }
    }

    /**
     * 导出excel通用方法(导出多个sheet .xls文件)重载
     * @param workbook
     * @param out        : OutputStream对象
     * @param limitNum   : 超过limitNum生成新sheet
     * @param sheetTitle : 设置excel的sheet标题
     * @param headers    : 设置excel的列标题
     * @param columnsize : 设置excel的列宽度
     * @param data       : List<HashMap<String,Object>> 数据
     * @throws IOException
     */
    public void exprotExcelManySheet(HSSFWorkbook workbook,OutputStream out,int limitNum,String sheetTitle,
            String[] headers,int [] columnsize,List<LinkedHashMap<String,Object>> data) throws IOException{
        setExcelData(workbook, out, limitNum, sheetTitle, headers, columnsize, data);
        workbook.write(out);
        out.flush();
        out.close();
    }

    /**
     * 导出excel通用方法(导出多个sheet .xls文件)
     * @param workbook
     * @param out        : OutputStream对象
     * @param limitNum   : 超过limitNum生成新sheet
     * @param sheetTitle : 设置excel的sheet标题
     * @param columnsize : 设置excel的列宽度
     * @param data       : List<HashMap<String,Object>> 数据
     * @throws IOException
     */
    public void exprotExcelManySheet(HSSFWorkbook workbook,OutputStream out,int limitNum,
            String sheetTitle,int [] columnsize,List<LinkedHashMap<String,Object>> data) throws IOException{
        setExcelData(workbook, out, limitNum, sheetTitle, columnsize, data);
        workbook.write(out);
        out.flush();
        out.close();
    }



    /**
     * 导出excel压缩包通用方法(导出多个sheet .zip文件)
     * @param workbook
     * @param limitNum   : 限制每个sheet最多多少条数据
     * @param sheetTitle : 每个sheet的name
     * @param headers    : sheet标题
     * @param result     : 传入的数据
     * @param out
     * @throws IOException
     */
    public void exprotExcelManySheetZip(HSSFWorkbook workbook,OutputStream out,int limitNum,String sheetTitle,
            String[] headers,int [] columnsize,List<LinkedHashMap<String,Object>> data) throws IOException{
         setExcelData(workbook, out, limitNum, sheetTitle, headers, columnsize, data);
         ZipOutputStream zip = new ZipOutputStream(out,Charset.forName("GBK"));
         ZipEntry entry = new ZipEntry(sheetTitle+".xls");//设置压缩包中文件的名字
         zip.putNextEntry(entry);
         workbook.write(zip);
         zip.flush();
         zip.close();
    }


    /**
     * 创建标题头
     * @param headers
     * @param titlestyle
     * @param row
     */
    public void createHeaders(String[] headers,HSSFCellStyle titlestyle,HSSFRow row){
        int headerslength = headers.length;
        for(int i =0;i<headerslength;i++){
            HSSFCell cell = row.createCell(i);
            HSSFRichTextString text = new HSSFRichTextString(headers[i]);
            cell.setCellStyle(titlestyle);
            cell.setCellValue(text.toString());
        }
    }

    /**
     * 创建标题头
     * @param data
     * @param titlestyle
     * @param row
     */
    public String [] createHeaders(List<LinkedHashMap<String,Object>> data,HSSFCellStyle titlestyle,HSSFRow row){
        int size = data.get(0).size(); 
        String [] headers = new String[size];
        Set<String> keys = data.get(0).keySet();
        Iterator iter = keys.iterator();
        int count = 0;
        while(iter.hasNext()){
            String str = (String) iter.next();
            headers[count] = str;
            HSSFCell cell = row.createCell(count);
            HSSFRichTextString text = new HSSFRichTextString(str);
            cell.setCellStyle(titlestyle);
            cell.setCellValue(text.toString());
            count++;
        }
        return headers;
    }

    /**
     * 设置正文单元格格式
     * @param workbook
     * @return
     */
    public  HSSFCellStyle createBodyCellStyle(HSSFWorkbook workbook){
        HSSFCellStyle cellstyle = workbook.createCellStyle();
        HSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short)10);
        font.setFontName(HSSFFont.FONT_ARIAL);
        cellstyle.setFont(font);
        cellstyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        return cellstyle;

    }

    /**
     * 设置标题单元样式
     * @param workbook
     * @return
     */
    public   HSSFCellStyle createTitleCellStyle(HSSFWorkbook workbook){
        HSSFCellStyle  cellstyle = workbook.createCellStyle();
        HSSFFont font = workbook.createFont();
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        font.setFontHeightInPoints((short)10);
        font.setFontName(HSSFFont.FONT_ARIAL);
        cellstyle.setFont(font);
        cellstyle.setFillForegroundColor(HSSFColor.SEA_GREEN.index);
        cellstyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        cellstyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        return cellstyle;
    }


    /**
     * excel 或者 zip 文件下载(表单提交,ajax请求不可以)
     * @param request
     * @param response
     * @param filepath
     * @param filename
     * @param out
     * @throws IOException
     */
    public void download(HttpServletRequest request,HttpServletResponse response,HSSFWorkbook workbook,String sheetTitle,String filename) throws IOException {
        // 以下主要实现 Excel文件下载
        // 设置响应头和下载保存的文件名
        response.reset();
        response.setContentType("APPLICATION/OCTET-STREAM");
        String xlsName ="ExpressCount.zip";
        String excelName = URLEncoder.encode(xlsName, "UTF-8");
         response.setHeader("Content-Disposition", "attachment; filename=\"" + excelName + "\"");
        String path = request.getSession().getServletContext().getRealPath("upload/excelexport/");
        String zipname ="ExpressCount";
        FileInputStream fis = new FileInputStream(path+zipname+".zip");   
        // 写出流信息   
        int i = 0;   
        while ((i=fis.read()) != -1) {   
             response.getOutputStream().write(i);   
        }
         fis.close();
         response.getOutputStream().flush();   
         response.getOutputStream().close();
    }



        /**
         *  excel 或者 zip 文件流下载(表单提交,ajax请求不可以)
         * @param path
         * @param response
         */
    public void downloadbyte(String path, HttpServletResponse response) {  
        try {  
            // path是指欲下载的文件的路径。  
            File file = new File(path);  
            // 取得文件名。  
            String filename = file.getName();  
            // 以流的形式下载文件。  
            InputStream fis = new BufferedInputStream(new FileInputStream(path));  
            byte[] buffer = new byte[fis.available()];  
            fis.read(buffer);  
            fis.close();  
            // 清空response  
            response.reset();  
            // 设置response的Header  
            response.addHeader("Content-Disposition", "attachment;filename="  
                    + new String(filename.getBytes()));  
            response.addHeader("Content-Length", "" + file.length());  
            OutputStream toClient = new BufferedOutputStream(  
                    response.getOutputStream());  
            response.setContentType("application/vnd.ms-excel;charset=gb2312");  
            toClient.write(buffer);  
            toClient.flush();  
            toClient.close();  
        } catch (IOException ex) {  
            ex.printStackTrace();  
        }  
    }  
}

/**
 * POIExcelUtils工具类
 */
public  class POIExcelUtils {

    /**
     * 导出多个sheet的excel(.xls文件)
     * @param request
     * @param result        : List<HashMap<String,Object>> 数据
     * @param filename      : 导出excel的名字
     * @param limitNum      : 超过limitNum生成新sheet
     * @param sheetTitle    : 设置excel的sheet标题
     * @param headers       : 设置excel的列标题
     * @param columnsize    : 设置excel的列宽度
     * @return
     * @throws IOException
     */
    public static String POIExcelExport(HttpServletRequest request,List<LinkedHashMap<String,Object>> result,String filename
            ,int limitNum,String sheetTitle,String [] headers,int[] columnsize) throws IOException{
        POIExcelExport poiexport = new POIExcelExport();
        HSSFWorkbook workbook = new HSSFWorkbook();
        String path = request.getSession().getServletContext().getRealPath("upload/excelexport/");
        //不存在就创建文件夹
        newFolder(path);
        OutputStream out = new FileOutputStream(path+filename);
        poiexport.exprotExcelManySheet(workbook, out, limitNum, sheetTitle, headers, columnsize, result);
        String downloadpath = "upload/excelexport/"+filename;
        return downloadpath;
    }

    /**
     * 导出多个sheet的excel(.xls文件)重载
     * @param request
     * @param result        : List<HashMap<String,Object>> 数据
     * @param filename      : 导出excel的名字
     * @param limitNum      : 超过limitNum生成新sheet
     * @param sheetTitle    : 设置excel的sheet标题
     * @param columnsize    : 设置excel的列宽度
     * @return
     * @throws IOException
     */
    public static String POIExcelExport(HttpServletRequest request,List<LinkedHashMap<String,Object>> result,
            String filename,int limitNum,String sheetTitle,int[] columnsize) throws IOException{
        POIExcelExport poiexport = new POIExcelExport();
        HSSFWorkbook workbook = new HSSFWorkbook();
        String path = request.getSession().getServletContext().getRealPath("upload/excelexport/");
        //不存在就创建文件夹
        newFolder(path);
        OutputStream out = new FileOutputStream(path+"/"+filename);
        poiexport.exprotExcelManySheet(workbook, out, limitNum, sheetTitle, columnsize, result);
        String downloadpath = "upload/excelexport/"+filename;
        return downloadpath;
    }


    /**
     * 导出多个sheet的excel压缩文件(.zip)
     * @param request
     * @param result        : List<HashMap<String,Object>> 数据
     * @param filename      : 导出excel的名字
     * @param limitNum      : 超过limitNum生成新sheet
     * @param sheetTitle    : 设置excel的sheet标题
     * @param headers       : 设置excel的列标题
     * @param columnsize    : 设置excel的列宽度
     * @throws IOException
     */
    public static String POIExcelExportZip(HttpServletRequest request,List<LinkedHashMap<String,Object>> result,String filename
            ,int limitNum,String sheetTitle,String [] headers,int[] columnsize) throws IOException{
        POIExcelExport poiexport = new POIExcelExport();
        HSSFWorkbook workbook = new HSSFWorkbook();
        String path = request.getSession().getServletContext().getRealPath("upload/excelexport/");
        //不存在就创建文件夹
        newFolder(path);
        OutputStream out = new FileOutputStream(path+filename);
        poiexport.exprotExcelManySheetZip(workbook, out, limitNum, sheetTitle, headers, columnsize, result);
        String zipdownloadpath = "upload/excelexport/"+filename;
        return zipdownloadpath;
    }


    /**
     * 传入的path不存在就创建文件夹
     * @param path
     * @return
     */
    public static boolean newFolder(String path){
        if(path == null || path==""){
            return false;
        }
        File file = new File(path);
        if(!file.exists()){
            file.mkdirs();
        }
        return true;
    }


    /**
     * 数据转换方法
     * 暂没用到
     * @param oldData
     * @param keys
     * @return
     */
    public static List<List<Object>> dataTransfer(List<HashMap<String,Object>> oldData, String[] keys){
        List<List<Object>> newData = new ArrayList<List<Object>>();
        for (HashMap<String,Object> object : oldData) {
            List<Object> row = new ArrayList<Object>();
            for (String key : keys){
                row.add(object.get(key));
            }
            newData.add(row);
        }
        return newData;
    }

    /**
     * 从hashMap中拿到key的数组(暂时没用到)
     * @param data
     * @return
     */
    public static String[] gethashMapKey(HashMap<String,Object> data){
        int size = data.size(); 
        String [] headers = new String[size];
        Set<String> keys = data.keySet();
        Iterator iter = keys.iterator();
        int count = 0;
        while(iter.hasNext()){
            String str = (String) iter.next();
            headers[count] = str;
            count++;
        }
        return headers;
    }
}   

我在页面上用的Ajax请求,然后后台返回一个excel生成的地址,跳转就可以下载,如果想要通过流的方式,那么不可以用ajax,因为ajax无法解析流.
甚至可以传入List<List<String,Object>>类型

导出6万条数据时间15秒左右,如果不设置列的宽度,还要更快.我试过用poi自带的自适应方法,发现效率变低很多,但是不设置宽度导出的excel很难看,所以我手动传入一个列宽度的数组,在降低点效率的同时又做到了美观..

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用Apache POI库来实现这个功能,下面是一个简单的示例代码: ```java import java.io.FileOutputStream; import java.io.IOException; import java.util.List; import java.util.ArrayList; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.xssf.streaming.SXSSFWorkbook; public class ExcelExporter { private static final int MAX_ROWS_PER_SHEET = 10000; public void exportToExcel(List<MyData> dataList, String filePath) throws IOException { // Create workbook SXSSFWorkbook workbook = new SXSSFWorkbook(); workbook.setCompressTempFiles(true); // Split data into sheets List<List<MyData>> sheetsData = splitDataIntoSheets(dataList); // Export each sheet for (int i = 0; i < sheetsData.size(); i++) { List<MyData> sheetData = sheetsData.get(i); String sheetName = "Sheet" + (i + 1); exportToSheet(sheetData, sheetName, workbook); } // Save the workbook try (FileOutputStream outputStream = new FileOutputStream(filePath)) { workbook.write(outputStream); } } private List<List<MyData>> splitDataIntoSheets(List<MyData> dataList) { List<List<MyData>> sheetsData = new ArrayList<>(); int numOfSheets = (int) Math.ceil((double) dataList.size() / MAX_ROWS_PER_SHEET); for (int i = 0; i < numOfSheets; i++) { int startIndex = i * MAX_ROWS_PER_SHEET; int endIndex = Math.min(startIndex + MAX_ROWS_PER_SHEET, dataList.size()); List<MyData> sheetData = dataList.subList(startIndex, endIndex); sheetsData.add(sheetData); } return sheetsData; } private void exportToSheet(List<MyData> dataList, String sheetName, SXSSFWorkbook workbook) { // Create sheet SXSSFSheet sheet = workbook.createSheet(sheetName); sheet.trackAllColumnsForAutoSizing(); // Create header row Row headerRow = sheet.createRow(0); headerRow.createCell(0).setCellValue("Column1"); headerRow.createCell(1).setCellValue("Column2"); headerRow.createCell(2).setCellValue("Column3"); // Populate data rows for (int i = 0; i < dataList.size(); i++) { MyData data = dataList.get(i); Row dataRow = sheet.createRow(i + 1); dataRow.createCell(0).setCellValue(data.getColumn1()); dataRow.createCell(1).setCellValue(data.getColumn2()); dataRow.createCell(2).setCellValue(data.getColumn3()); } // Autosize columns for (int i = 0; i < 3; i++) { sheet.autoSizeColumn(i); } } } ``` 这个示例代码使用了SXSSFWorkbook来支持大量数据导出。它会将数据按照每个sheet最多10000条的规则进行分割,然后在每个sheet里面写入数据。最后将所有sheet写入到一个文件里面。 你需要提供一个MyData类,它包含了你要导出数据的字段。在示例代码里面,它包含了三个字段:column1、column2和column3。 你需要创建一个ExcelExporter实例,并调用它的exportToExcel方法来执行导出操作。它需要两个参数:一个是你的数据列表,另一个是导出文件的路径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值