【java实现多sheet页Excel压缩导出,并指定其中一个Excel动态指定合并单元格,并压缩后将路径给前端下载文件】


以下为前端下载解压打开的效果图:
在这里插入以下为效果图图片描述

一、将表头字段排序

使用LinkedList(){{}};目的是为了后面将表头字段有序写入Excel。

        // 第一张表:下发总量统计表
        String fileNameP1="第一张表(表下面的名称)";
        String tableNameP1="统计表(表名)";
        List<String>headerP1=new LinkedList<String>(){{
            add("序号");add("字段一");add("字段二");add("字段三");add("字段四");add("字段五");add("备注");
        }
        };
        // 第二张表
        String fileNameP2="第二张表(表下面的名称)";
        String tableNameP2="台账统计表";
        List<String>headerP2=new LinkedList<String>(){{
            add("序号");add("字段一");add("字段二");add("字段三");add("字段四");add("字段五");add("字段六");
            add("字段七");add("字段八");add("备注");add("字段九");add("字段十");
        }
        };
        // 第三张表:条目详细表
        String fileNameP3="第三张表(表下面的名称)";
        String tableNameP3="详细表";
        List<String>headerP3=new LinkedList<String>(){{
            add("字段一");add("字段二");add("字段三");add("字段四");add("字段五");add("字段六");
            add("字段七");add("字段八");add("字段九");add("字段十");
        }
        };

二、DownloadServiceImp.java(将数据排序)

 Result<List<List<Map<String, Object>>>> dataListP1 = stateService.queryTaskStateTable(参数1, 参数2, null, null, null, null,null,null);//查询第一张表
                Result<LinkedList> dataListP2 = stateService.queryTaskStateOfTable(参数1, 参数2, null, null, null, null,null,null,null);//查询第二张表
                Result<LinkedList<LinkedList<BatchSupplyLandInfo>>>dataListP3 = stateService.queryDownloadGrant(参数1, 参数2, null, null, null, null, null, null, null);//查询第三张表

                List<List<Map<String, Object>>> data1 = dataListP1.getData();
                List<Map<String,Object>>dataListP11=data1.get(0);//提取地一张表数据

                LinkedList<GrantLandInfo> data2 = dataListP2.getData();//获取第二张表数据

                LinkedList<LinkedList<BatchSupplyLandInfo>> data3 = dataListP3.getData();//获取第三张表数据
//以上可根据个人或项目需求,拿数据,这里将不会把获取数据的Service、mapper和XML展示出来

                //三张表的数据需进一步有序排列
                LinkedList<String> rowData1= new LinkedList<>();
                LinkedList<String>rowData2 = new LinkedList<>();
                LinkedList<String>rowData3 = new LinkedList<>();

                //第一张表:按所给标准表格字段,将数据排序
                for (Map<String,Object>data:dataListP11){//遍历第一份数据
                    List<String>dataTem1 = new LinkedList<>();
                    for(int i=0;i<data.size();i++){
                        dataTem1=new LinkedList<String>(){{
                            add(String.valueOf(Optional.ofNullable(data.get("id")).orElse("")));
                            add(String.valueOf(Optional.ofNullable(data.get("字段一")).orElse("")));
                            add(String.valueOf(Optional.ofNullable(data.get("字段二")).orElse("")));
                            add(String.valueOf(Optional.ofNullable(data.get("字段三")).orElse("")));
                            add(String.valueOf(Optional.ofNullable(data.get("字段四")).orElse("")));
                            add(String.valueOf(Optional.ofNullable(data.get("字段五")).orElse("")));
                            add(String.valueOf(Optional.ofNullable(data.get("bz")).orElse("")));
                        }};
                    }
                    rowData1.add(String.valueOf(dataTem1));
                }

                //第二张表:按所给标准表格字段,将数据排序
                for (int j=0;j<data2.size();j++){
                    int finalJ = j;
                    List<String>dataTem2=new LinkedList<String>(){{
                            add(Optional.ofNullable(data2.get(finalJ).getXh()).orElse(""));
                            add(Optional.ofNullable(data2.get(finalJ).getzdyName()).orElse(""));
                            add(Optional.ofNullable(data2.get(finalJ).getzdeName()).orElse(""));
                            add(Optional.ofNullable(data2.get(finalJ).getzdsName()).orElse(""));
                            add(Optional.ofNullable(data2.get(finalJ).getzdw()).orElse(""));
                            add(Optional.ofNullable(data2.get(finalJ).getzdl()).orElse(""));
                            add(Optional.ofNullable(data2.get(finalJ).getzdq()).orElse(""));
                            add(Optional.ofNullable(data2.get(finalJ).getzdb()).orElse(""));
                            add(Optional.ofNullable(data2.get(finalJ).getzdj()).orElse(""));
                            add(Optional.ofNullable(data2.get(finalJ).getRemark()).orElse(""));
                            add(Optional.ofNullable(data2.get(finalJ).getzds()).orElse(""));
                            add(Optional.ofNullable(data2.get(finalJ).getzdsy()).orElse(""));
                        }};
                    rowData2.add(String.valueOf(dataTem2));

                }

                //第三张表:按所给标准表格字段,将数据排序
                for (LinkedList<BatchSupplyLandInfo>data:data3){
                    List<String>dataTem3 = new LinkedList<>();
                    for(int i=0;i<data.size();i++){
                        int finalI = i;
                        dataTem3=new LinkedList<String>(){{
                            add((Optional.ofNullable(data.get(finalI).getCountyPacName()).orElse("")));
                            add((Optional.ofNullable(data.get(finalI).getName()).orElse("")));
                            add((Optional.ofNullable(data.get(finalI).getApprovalNumber()).orElse("")));
                            add((Optional.ofNullable(data.get(finalI).getBatchSumArea()).orElse("")));//汇总

                            add((Optional.ofNullable(data.get(finalI).getGrantLandArea()).orElse("")));
                            add((Optional.ofNullable(data.get(finalI).getProjectName()).orElse("")));
                            add((Optional.ofNullable(data.get(finalI).getRegulatoryNumber()).orElse("")));
                            add((Optional.ofNullable(data.get(finalI).getAgreedDate()).orElse("")));
                            add((Optional.ofNullable(data.get(finalI).getSupplyArea()).orElse("")));

                            add((Optional.ofNullable(data.get(finalI).getSupplySumArea()).orElse("")));
                        }};

                        rowData3.add(String.valueOf(dataTem3));
                    }

                }

                //批而未供有三张表
                ExcelExp excelExp1=new ExcelExp(fileNameP1, headerP1, rowData1,tableNameP1);
                ExcelExp excelExp2=new ExcelExp(fileNameP2, headerP2, rowData2,tableNameP2);
                ExcelExp excelExp3=new ExcelExp(fileNameP3, headerP3, rowData3,tableNameP3);
                list.add(excelExp1);
                list.add(excelExp2);
                list.add(excelExp3);
                Workbook workbook=POIUtils.exportManySheetExcel(list);

三、ExcelExp.java(存Excel的属性)

package com.hk.dfgag.utils.excelDeal;

import lombok.Data;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

@Data
public class ExcelExp {
    private String fileName;//sheet的名称
    private List<String> handers;//sheet里的Excel名称
    private LinkedList<String>dataset;//sheet里的数据集
    private String tableName;//表名


    public ExcelExp(String fileName, List<String>handers, LinkedList<String> dataset, String tableName){
        this.fileName=fileName;
        this.handers=handers;
        this.dataset=dataset;
        this.tableName=tableName;
    }
    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public List<String> getHanders() {
        return handers;
    }

    public void setHanders(List<String> handers) {
        this.handers = handers;
    }

    public LinkedList<String> getDataset() {
        return dataset;
    }

    public void setDataset(LinkedList<String> dataset) {
        this.dataset = dataset;
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

}

四、POIUtils.java(最重要的一步,需合并的地方在这里操作)

package com.hk.dfgag.utils.excelDeal;
import java.util.*;

@Component
public class POIUtils {
    /**
     * @param @param file 导出文件路径
     * @param @param mysheets
     * @return void
     * @throws
     * @Title: exportManySheetExcel
     * @Description: 可生成单个、多个sheet
     */

    public static Workbook exportManySheetExcel(List<ExcelExp> mysheets) {

        HSSFWorkbook wb = new HSSFWorkbook();// 创建工作薄
        List<ExcelExp> sheets = mysheets;

        // 表头样式
        HSSFCellStyle style = wb.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER); // 创建一个居中格式
        //设置边框样式
        style.setBorderBottom(BorderStyle.THIN); //下边框
        style.setBorderLeft(BorderStyle.THIN);//左边框
        style.setBorderTop(BorderStyle.THIN);//上边框
        style.setBorderRight(BorderStyle.THIN);//右边框
        // 字体样式
        HSSFFont fontStyle = wb.createFont();
        fontStyle.setFontName("微软雅黑");
        fontStyle.setFontHeightInPoints((short) 20);
        // fontStyle.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        style.setFont(fontStyle);
        int flag=0;//标记第几张表
        for (ExcelExp excel : sheets) {
            flag++;
            // 新建一个sheet
            HSSFSheet sheet = wb.createSheet(excel.getFileName());// 获取该sheet名称

            List<String> handers = excel.getHanders();// 获取sheet的标题名

            HSSFRow tableName = sheet.createRow(0);
            HSSFCell cellName = tableName.createCell(0);
            sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, handers.size()-1));
            HSSFCellStyle titleStyle = wb.createCellStyle();
            // 设置单元格样式
            HSSFFont titleFont = wb.createFont(); // 标题字体
            titleFont.setFontHeightInPoints((short) 12); // 字号
            titleStyle.setFont(titleFont);
            titleStyle.setAlignment(HorizontalAlignment.CENTER);
            titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            titleStyle.setBorderBottom(BorderStyle.THIN); //下边框
            titleStyle.setBorderLeft(BorderStyle.THIN);//左边框
            titleStyle.setBorderTop(BorderStyle.THIN);//上边框
            titleStyle.setBorderRight(BorderStyle.THIN);//右边框

            cellName.setCellStyle(style);//加表头的样式
            // 设置单元格内容
            cellName.setCellValue(excel.getTableName());//

            HSSFRow rowFirst = sheet.createRow(1);// 第一个sheet的第一行为标题
            // 写标题
            for (int i = 0; i < handers.size(); i++) {
                // 获取第一行的每个单元格
                HSSFCell cell = rowFirst.createCell(i);
                // 往单元格里写数据
                cell.setCellValue(handers.get(i));
                cell.setCellStyle(titleStyle); // 加字段的样式
                sheet.setColumnWidth(i, 4000); // 设置每列的列宽
            }

            // 写数据集
            LinkedList<String> dataset = excel.getDataset();
            String newData="";
            String oldData="";
            Cell hc;
            int flag1=0;//数据标记
            int hNum=0;//行数标记


            if(flag==3){//特殊处理第三张表
                Map<String, List<Integer>> mergeRowMap = new HashMap<>();//将字段相同的下标和字段做记录
                for (int i=0;i<dataset.size();i++){//里面的字段如[[a,b,c,d],[a,b,c,d1],[a,b,c,d1],[a,b,c,d1],[a,b,c,d1],[a,b,c,d1],[a,b,c,d1]……]
                    newData=dataset.get(i).replaceAll("[\\[\\]]","");//获取的数据为"[a,b,c,d]",现需要将中括号去掉,进行下一步的处理
                    String[] apNew= newData.split(",");//转为数组,以逗号分割
                    List<Integer>orDefault=mergeRowMap.getOrDefault(apNew[2],new ArrayList<>());//apNew[2],以c字段作key,记录相同的c字段下标
                    orDefault.add(i);
                    mergeRowMap.put(apNew[2],orDefault);
                }

                for (int i = 0; i < dataset.size(); i++) {
                    // 创建数据行,将所有数据装进表格中
                    HSSFRow row = sheet.createRow(i + 2);
                    String k=dataset.get(i).replaceAll("[\\[\\]]","");
                    String[] k1= k.split(",");
                    for(int j=0;j<k1.length;j++){//处理第一二张表数据
                        Cell cell=row.createCell(j);
                        cell.setCellValue(k1[j]);
                        cell.setCellStyle(titleStyle);//加数据的样式
                    }
                }

                //开始合并单元格
                mergeRowMap.forEach((apNew, rowIndexs) -> {
                    if (rowIndexs.size() > 1) {
                        //4个参数,依次为:合并开始行、合并结束行、合并开始列、合并结束列,
                        //假如有10个相同的字段c,rowIndexs.get(0)指的是第一个相同字段c的下标1,因为有表头和表字段,所以要隔两行,要+2;
                        //(rowIndexs.size()-1)字段c的size为10,因从0开始,所以要减1,才能rowIndexs.get();  否则就会溢出,报错,同样要移两行,所以要在整个外面加2,这里的加2真的要注意,不是加在里面。         
                        CellRangeAddress rangeAddress1 = new CellRangeAddress(rowIndexs.get(0)+2, rowIndexs.get(rowIndexs.size()-1)+2, 0, 0);//第一个字段要合并
                        CellRangeAddress rangeAddress2= new CellRangeAddress(rowIndexs.get(0)+2, rowIndexs.get(rowIndexs.size()-1)+2, 1, 1);//第二个字段要合并
                        CellRangeAddress rangeAddress3= new CellRangeAddress(rowIndexs.get(0)+2, rowIndexs.get(rowIndexs.size()-1)+2, 2, 2);//第三个字段要合并
                        CellRangeAddress rangeAddress4= new CellRangeAddress(rowIndexs.get(0)+2, rowIndexs.get(rowIndexs.size()-1)+2, 3, 3);//第四个字段要合并
                        CellRangeAddress rangeAddress5= new CellRangeAddress(rowIndexs.get(0)+2, rowIndexs.get(rowIndexs.size()-1)+2, 4, 4);
                        CellRangeAddress rangeAddress6= new CellRangeAddress(rowIndexs.get(0)+2, rowIndexs.get(rowIndexs.size()-1)+2, 9, 9);//最后一个字段要合并
                        //添加要合并地址到表格
                        sheet.addMergedRegion(rangeAddress1);
                        sheet.addMergedRegion(rangeAddress2);
                        sheet.addMergedRegion(rangeAddress3);
                        sheet.addMergedRegion(rangeAddress4);
                        sheet.addMergedRegion(rangeAddress5);
                        sheet.addMergedRegion(rangeAddress6);
                    }
                });
            }else {
                for(int i=0;i<dataset.size();i++){
                    // 创建数据行
                    HSSFRow row = sheet.createRow(i + 2);
                    String k=dataset.get(i).replaceAll("[\\[\\]]","");
                    String[] k1= k.split(",");
                    for(int j=0;j<k1.length;j++){//处理第一二张表数据
                        Cell cell=row.createCell(j);
                        cell.setCellValue(k1[j]);
                        cell.setCellStyle(titleStyle);

                    }
                }

            }

        }
        return wb;
    }

}

五、DownloadServiceImp.java(在第二步完成后,接着写,将Excel压缩下载到前端,并删除本地)

   //导出数据到Excel
            FileOutputStream fileOutputStream=null;
            try{
                 baseFilePath = xlsFolder + File.separator + RandomUtil.randomString(10);
                if (!new File(baseFilePath).exists()) {
                    new File(baseFilePath).mkdirs();
                }
               filePath = baseFilePath +"//统计.xls";//为整个文件夹的名称,
               //在最外层声明String baseFilePath = "";//文件夹路径
               // String filePath = "";//文件路径
                fileOutputStream=new FileOutputStream(filePath);
                workbook.write(fileOutputStream);
                fileOutputStream.flush();
            }catch (FileNotFoundException e){
                e.printStackTrace();
            }catch (IOException e){
                e.printStackTrace();
            }finally {
                if(fileOutputStream!=null){
                    try{
                        // 上传成功
                        fileOutputStream.close();

                        // 开始压缩
                        String zipFile=baseFilePath +File.separator + "统计.zip";
                        try(FileOutputStream fos = new FileOutputStream(zipFile);
                            ZipOutputStream zos = new ZipOutputStream(fos);) {
                            File fileToZip = new File(filePath);//将写有数据的文件放入压缩包中
                            zipFile(fileToZip, fileToZip.getName(), zos);
                        } catch (Exception ignored) {}

                        // 将压缩包上传到minio
                        String downloadUrl = null;
                        try {
                            String objectName = "download/"+ CommonUtils.getUUID()+"/统计.zip";
                            MinioResult minioResult = DownloadServiceImp.minioUtil.upload(new File(zipFile), objectName);
                            if (minioResult.getCode().equals(200)) {
                                // 上传成功
                                downloadUrl = DownloadServiceImp.minioUtil.getDownloadUrl(objectName);
                                // 插入下载记录
                                // 插入下载记录
                                DownloadRecord downloadRecord = new DownloadRecord();
                                downloadRecord.setCreateTime(new Date());
                                downloadRecord.setLoginAccount(user.getLoginAccount());
                                downloadRecord.setPath(objectName);
                                downLoadMapper.addRecord(downloadRecord);
                            }
                            //返回前端后,清除本地文件
                            FileUtil.del(baseFilePath);
//                            FileUtil.del(baseFilePath);
                        } catch (Exception e) {}
                        if(downloadUrl!=null){
                            return Result.success(downloadUrl,"导出成功!");//给前端返回downloadUrl,直接Window。open(downloadUrl);即可下载
                        }
                    }catch (IOException e){
                        e.printStackTrace();
                    }
                }
            }

在项目中写这个接口之前,我没有做过后端关于表格的操作、也没有写过下载,很多都不懂,遇到很多细小的错,耽误了很多时间,写完之后才发现,其实是简单的,没有必要花这么多时间,所以在这里做个记录,以我小白的角度写一下,可能有点冗余,希望以后会慢慢改进。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值