EasyExcel生成多个exel文件并zip压缩

前言

最近项目上有个关于excel导出的需求,要求如下:
1,表头除了固定的几个,可以动态添加,比如下面表格,范围1,时间,值是固定,其他的表头都是动态的
2,范围1,范围2,范围3是合并列
3,范围2,范围3是联动的
4,自适应宽高,自适应居中,样式设置
5,生成多个excel最后zip压缩

注意:
1,因为产品的需求,合并列范围1,范围2,范围3严格遵守合并的格式,并不是任意合并,所以比较复杂。
2,不支持列与列之间的合并,如果想要支持,可以基于此demo开发是没任何问题的。

在这里插入图片描述

POM

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.5.0</version>
        </dependency>


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.0.5</version>
        </dependency>


        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.2.5</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.22</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.1</version>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.8.0</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.7</version>
        </dependency>

设计

1,数据库获取数据用List<Map<String,Object>>,后面需要转换成List<List>(原因:easyexcel对List不兼容)

代码如下

压缩工具类

public class ZipUtils {

    private static final Charset DEFAULT_CHARSET = Charset.defaultCharset();

    /**
     * 将文件流压缩到目标流中
     *
     * @param out       目标流,压缩完成自动关闭
     * @param fileNames 流数据在压缩文件中的路径或文件名
     * @param ins       要压缩的源,添加完成后自动关闭流
     */
    public static void zip(OutputStream out, List<String> fileNames, List<InputStream> ins) {
        zip(out, fileNames.toArray(new String[0]), ins.toArray(new InputStream[0]));
    }

    /**
     * 将文件流压缩到目标流中
     *
     * @param out       目标流,压缩完成自动关闭
     * @param fileNames 流数据在压缩文件中的路径或文件名
     * @param ins       要压缩的源,添加完成后自动关闭流
     */
    public static void zip(File out, List<String> fileNames, List<InputStream> ins) throws IOException {
        FileOutputStream outputStream = new FileOutputStream(out);
        zip(outputStream, fileNames.toArray(new String[0]), ins.toArray(new InputStream[0]));
        outputStream.flush();
    }

    /**
     * 将文件流压缩到目标流中
     *
     * @param out       目标流,压缩完成自动关闭
     * @param fileNames 流数据在压缩文件中的路径或文件名
     * @param ins       要压缩的源,添加完成后自动关闭流
     */
    public static void zip(OutputStream out, String[] fileNames, InputStream[] ins) {
        ZipOutputStream zipOutputStream = null;
        try {
            zipOutputStream = getZipOutputStream(out, DEFAULT_CHARSET);
            zip(zipOutputStream, fileNames, ins);
        } catch (IOException e) {
//            throw new Exception("压缩包导出失败!", e);
        } finally {
            IOUtils.closeQuietly(zipOutputStream);
        }
    }

    /**
     * 将文件流压缩到目标流中
     *
     * @param zipOutputStream 目标流,压缩完成不关闭
     * @param fileNames       流数据在压缩文件中的路径或文件名
     * @param ins             要压缩的源,添加完成后自动关闭流
     * @throws IOException IO异常
     */
    public static void zip(ZipOutputStream zipOutputStream, String[] fileNames, InputStream[] ins) throws IOException {
        if (ArrayUtils.isEmpty(fileNames) || ArrayUtils.isEmpty(ins)) {
            throw new IllegalArgumentException("文件名不能为空!");
        }
        if (fileNames.length != ins.length) {
            throw new IllegalArgumentException("文件名长度与输入流长度不一致!");
        }
        for (int i = 0; i < fileNames.length; i++) {
            add(ins[i], fileNames[i], zipOutputStream);
        }
    }

    /**
     * 添加文件流到压缩包,添加后关闭流
     *
     * @param in       需要压缩的输入流,使用完后自动关闭
     * @param fileName 压缩的路径
     * @param out      压缩文件存储对象
     * @throws IOException IO异常
     */
    private static void add(InputStream in, String fileName, ZipOutputStream out) throws IOException {
        if (null == in) {
            return;
        }
        try {
            out.putNextEntry(new ZipEntry(fileName));
            IOUtils.copy(in, out);
        } catch (IOException e) {
            throw new IOException(e);
        } finally {
            IOUtils.closeQuietly(in);
            closeEntry(out);
        }
    }

    /**
     * 获得 {@link ZipOutputStream}
     *
     * @param out     压缩文件流
     * @param charset 编码
     * @return {@link ZipOutputStream}
     */
    private static ZipOutputStream getZipOutputStream(OutputStream out, Charset charset) {
        if (out instanceof ZipOutputStream) {
            return (ZipOutputStream) out;
        }
        return new ZipOutputStream(out,  DEFAULT_CHARSET);
    }

    /**
     * 关闭当前Entry,继续下一个Entry
     *
     * @param out ZipOutputStream
     */
    private static void closeEntry(ZipOutputStream out) {
        try {
            out.closeEntry();
        } catch (IOException e) {
            // ignore
        }
    }


}

自适应宽度

mport com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.CellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CustomCellWriteWeightStrategy extends AbstractColumnWidthStyleStrategy {
    private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap<>();

    @Override
    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer integer, Boolean isHead) {
        boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
        if (needSetWidth) {
            Map<Integer, Integer> maxColumnWidthMap = CACHE.get(writeSheetHolder.getSheetNo());
            if (maxColumnWidthMap == null) {
                maxColumnWidthMap = new HashMap<>();
                CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);
            }

            Integer columnWidth = this.dataLength(cellDataList, cell, isHead);
            if (columnWidth >= 0) {
                if (columnWidth > 254) {
                    columnWidth = 254;
                }

                Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
                if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
                    maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);
                    Sheet sheet = writeSheetHolder.getSheet();
                    sheet.setColumnWidth(cell.getColumnIndex(), columnWidth * 256);
                }

            }
        }
    }

    /**
     * 计算长度
     * @param cellDataList
     * @param cell
     * @param isHead
     * @return
     */
    private Integer dataLength(List<WriteCellData<?>>  cellDataList, Cell cell, Boolean isHead) {
        if (isHead) {
            return cell.getStringCellValue().getBytes().length;
        } else {
            CellData cellData = cellDataList.get(0);
            CellDataTypeEnum type = cellData.getType();
            if (type == null) {
                return -1;
            } else {
                switch (type) {
                    case STRING:
                        // 换行符(数据需要提前解析好)
                        int index = cellData.getStringValue().indexOf("\n");
                        return index != -1 ?
                                cellData.getStringValue().substring(0, index).getBytes().length + 1 : cellData.getStringValue().getBytes().length + 1;
                    case BOOLEAN:
                        return cellData.getBooleanValue().toString().getBytes().length;
                    case NUMBER:
                        return cellData.getNumberValue().toString().getBytes().length;
                    default:
                        return -1;
                }
            }
        }
    }
}

自适应高度

import com.alibaba.excel.write.style.row.AbstractRowHeightStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

import java.util.Iterator;

public class CustomCellWriteHeightStrategy extends AbstractRowHeightStyleStrategy {
    /**
     * 默认高度
     */
    private static final Integer DEFAULT_HEIGHT = 300;

    @Override
    protected void setHeadColumnHeight(Row row, int relativeRowIndex) {
    }

    @Override
    protected void setContentColumnHeight(Row row, int relativeRowIndex) {
        Iterator<Cell> cellIterator = row.cellIterator();
        if (!cellIterator.hasNext()) {
            return;
        }

        // 默认为 1行高度
        Integer maxHeight = 1;
        while (cellIterator.hasNext()) {
        Cell cell = cellIterator.next();
            switch (cell.getCellType()) {
                case STRING:
                    if (cell.getStringCellValue().contains("\n")) {
                        int length = cell.getStringCellValue().split("\n").length;
                        maxHeight = Math.max(maxHeight, length);
                    }
                    break;
                default:
                    break;
            }
        }

        row.setHeight((short) (maxHeight * DEFAULT_HEIGHT));

    }
}

自适应居中及字体设置

    //设置样式 去除默认表头样式及设置内容居中
    public static HorizontalCellStyleStrategy getStyleStrategy(){
        //内容样式策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //垂直居中,水平居中
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
        contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
        contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
        contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
        //设置 自动换行
        contentWriteCellStyle.setWrapped(true);
        // 字体策略
        WriteFont contentWriteFont = new WriteFont();
        // 字体大小
        contentWriteFont.setFontHeightInPoints((short) 12);
        contentWriteCellStyle.setWriteFont(contentWriteFont);
        //头策略使用默认
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    }

合并策略

import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import com.yueyang.util.MergeParam;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

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

public class BizMergeStrategy  extends AbstractMergeStrategy {

    private Map<String, List<MergeParam>> strategyMap;
    private Sheet sheet;

    public BizMergeStrategy(Map<String, List<MergeParam>> strategyMap) {
        this.strategyMap = strategyMap;
    }

    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, Integer integer) {
        this.sheet = sheet;
        if (cell.getRowIndex() == 1 && cell.getColumnIndex() == 0) {
            /**
             * 保证每个cell被合并一次,如果不加上面的判断,因为是一个cell一个cell操作的,
             * 例如合并A2:A3,当cell为A2时,合并A2,A3,但是当cell为A3时,又是合并A2,A3,
             * 但此时A2,A3已经是合并的单元格了
             */
            for (Map.Entry<String, List<MergeParam>> entry : strategyMap.entrySet()) {
                Integer columnIndex = Integer.valueOf(entry.getKey());
                entry.getValue().forEach(rowRange -> {
                    //添加一个合并请求
                    sheet.addMergedRegionUnsafe(new CellRangeAddress(rowRange.getStart(),
                            rowRange.getEnd(), columnIndex, columnIndex));
                });
            }
        }
    }
}

对象类

数据库查询的映射类

import lombok.Data;

@Data
public class XxglFieldDefine {

    private String fieldName;

    private String fieldKey;
}

合并基础类

import lombok.Data;

@Data
public class MergeParam {

    private int start;
    private int end;
}

合并列枚举

import lombok.Getter;

@Getter
public enum  MergeColumnEnum {
    /**
     * 通知消息模板
     */
    MERGE_COLUMN1("column1", "范围1"),
    MERGE_COLUMN2("column2", "范围2"),
    MERGE_COLUMN3("column3", "范围3"),
    ;
    private final String mergeColumn;
    private final String desc;

    MergeColumnEnum(String code, String title) {
        this.mergeColumn = code;
        this.desc = title;
    }
}

主要代码

 @Resource
    private DataDbMapper mapper;

    @GetMapping("/test")
    @ApiOperation("/test")
    public List<Map<String, Object>> test() throws Exception {
        List<Map<String, Object>> dataMap = mapper.getMap();

        Map<String, List<MergeParam>> mergeMap = getMergeMap(dataMap);



        List<InputStream> ins = new ArrayList<>();
        // 压缩包内流的文件名
        List<String> paths = new ArrayList<>();
        for (int i = 0; i < 2; i++) {
            // 使用 easyExcel 写到 OutputStream
            String moduleName="moudle_"+System.currentTimeMillis();
            ins.add(writeExcel6(mergeMap, dataMap,moduleName));
            paths.add(moduleName+".xlsx");
        }
        // 保存的 zip 文件名
        File zipFile = new File("E:\\excel\\noModelWrite.zip");


        ZipUtils.zip(zipFile, paths, ins);

        return dataMap;
    }

    /**
     *  自适应合并居中,接list数据 对象固定
     *  1,长度,宽度无变化
     *
     *  数据为  map
     *  head为可变类型
     * @param map
     * @param map1
     */
    public static InputStream writeExcel6(Map<String, List<MergeParam>> map, List<Map<String, Object>> map1,String module) {
        // 使用 easyExcel 写到 OutputStream
        OutputStream out = new ByteArrayOutputStream();
        //这里自定义一个单元格的格式(标黄的行高亮显示)
        ExcelWriter excelWriter = EasyExcel.write(out).excelType(ExcelTypeEnum.XLSX).build();


        List<List<Object>> dataList = new ArrayList<List<Object>>();


        List<XxglFieldDefine> fList = getXxglFieldDefines();

        String[] arry = new String[fList.size()];
        for(int i=0; i<fList.size();i++){
            arry[i] = fList.get(i).getFieldKey();
        }
        //设置导出的数据内容
        for (Map<String, Object> m : map1) {
            List<Object> data = new ArrayList<Object>();
            for (int i = 0; i < arry.length; i++) {
                data.add(m.get(arry[i]));
            }
            dataList.add(data);
        }

        // 写sheet的时候注册相应的自定义合并单元格策略
        WriteSheet writeSheet = EasyExcel.writerSheet(module).head(createHeadByFields(head1()))
                .registerWriteHandler(new BizMergeStrategy( map))
                .registerWriteHandler(new CustomCellWriteWeightStrategy())
                .registerWriteHandler(new CustomCellWriteHeightStrategy())
                .registerWriteHandler(getStyleStrategy())
                .build();
        excelWriter.write(dataList, writeSheet);
        excelWriter.finish();
        return outputStream2InputStream(out);
    }

    /**
     * 输出流转输入流;数据量过大请使用其他方法
     *
     * @param out
     * @return
     */
    private static ByteArrayInputStream outputStream2InputStream(OutputStream out) {
        Objects.requireNonNull(out);
        ByteArrayOutputStream bos;
        bos = (ByteArrayOutputStream) out;
        return new ByteArrayInputStream(bos.toByteArray());
    }


    /**
     * 动态头 列设置
     * @return
     */
    private static  List<String> head1() {
        List<String> head0 = new ArrayList<String>();
        head0.add("范围1" );
        head0.add("范围2" );
        head0.add("范围3" );
        head0.add("时间" );
        head0.add("值" );
        head0.add("排序" );
        head0.add("主键id" );

        return head0;
    }
    //设置样式 去除默认表头样式及设置内容居中
    public static HorizontalCellStyleStrategy getStyleStrategy(){
        //内容样式策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //垂直居中,水平居中
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
        contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
        contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
        contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
        //设置 自动换行
        contentWriteCellStyle.setWrapped(true);
        // 字体策略
        WriteFont contentWriteFont = new WriteFont();
        // 字体大小
        contentWriteFont.setFontHeightInPoints((short) 12);
        contentWriteCellStyle.setWriteFont(contentWriteFont);
        //头策略使用默认
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    }



    private static List<List<String>> createHeadByFields(List<String> headList) {
        return headList.stream().map(Collections::singletonList).collect(Collectors.toList());
    }

    /**
     * 查询的数据对应的key,记住 顺序和设置动态头的顺序一定要一致
     * @return
     */
    private static List<XxglFieldDefine> getXxglFieldDefines() {
        List<XxglFieldDefine> fList  = new ArrayList<XxglFieldDefine>();
        XxglFieldDefine x = new XxglFieldDefine();
        x.setFieldName("范围1");
        x.setFieldKey("column1");
        fList.add(x);

        XxglFieldDefine x1 = new XxglFieldDefine();
        x1.setFieldName("范围2");
        x1.setFieldKey("column2");
        fList.add(x1);

        XxglFieldDefine x2 = new XxglFieldDefine();
        x2.setFieldName("范围3");
        x2.setFieldKey("column3");
        fList.add(x2);
        XxglFieldDefine x3 = new XxglFieldDefine();
        x3.setFieldName("date");
        x3.setFieldKey("date");
        fList.add(x3);

        XxglFieldDefine x4 = new XxglFieldDefine();
        x4.setFieldName("value");
        x4.setFieldKey("value");
        fList.add(x4);

        XxglFieldDefine x5 = new XxglFieldDefine();
        x5.setFieldName("sort");
        x5.setFieldKey("sort");
        fList.add(x5);

        XxglFieldDefine x6 = new XxglFieldDefine();
        x6.setFieldName("id");
        x6.setFieldKey("id");
        fList.add(x6);
        return fList;
    }

    /**
     * 获取范围1 范围2 范围3 合并数据
     * @param dataMap
     * @return
     */
    private Map<String, List<MergeParam>> getMergeMap(List<Map<String, Object>> dataMap) {
        Map<String, List<MergeParam>> map = new HashMap<>();
        //确定合并的字段有几个

        Map<Object, Integer> column1Map = new LinkedHashMap<>();
        Map<Object, Integer> column2Map = new LinkedHashMap<>();
        Map<Object, Integer> column3Map = new LinkedHashMap<>();
        List<MergeParam> column1List = new ArrayList<>();
        List<MergeParam> column2List = new ArrayList<>();
        List<MergeParam> column3List = new ArrayList<>();
        Boolean firstBool = true;
        int start = 0;
        for (Map<String, Object> stringObjectMap : dataMap) {
            start++;
            if (stringObjectMap.containsKey(MergeColumnEnum.MERGE_COLUMN1.getMergeColumn())) {
                Object column1Obj = stringObjectMap.get(MergeColumnEnum.MERGE_COLUMN1.getMergeColumn());
                if (column1Map.containsKey(column1Obj)) {
                    //说明已经存进去了
                    column1Map.put(column1Obj, column1Map.get(column1Obj) + 1);
                    if (stringObjectMap.containsKey(MergeColumnEnum.MERGE_COLUMN2.getMergeColumn())) {
                        Object column2Obj = stringObjectMap.get(MergeColumnEnum.MERGE_COLUMN2.getMergeColumn());
                        if (column2Map.containsKey(column2Obj)) {
                            //说明已经存进去了
                            column2Map.put(column2Obj, column2Map.get(column2Obj) + 1);
                            if (stringObjectMap.containsKey(MergeColumnEnum.MERGE_COLUMN3.getMergeColumn())) {
                                Object o = stringObjectMap.get(MergeColumnEnum.MERGE_COLUMN3.getMergeColumn());
                                if (column3Map.containsKey(o)) {
                                    //说明已经存进去了
                                    column3Map.put(o, column3Map.get(o) + 1);
                                } else {
                                    column3Map.put(o, 1);
                                }
                            }
                        } else {
                            //说明合并字段等级2的已经结束,需要处理生成合并字段等级3的合并数据
                            column2Map.put(column2Obj, 1);
                            //开始处理
                            column3List.addAll(getMergeParamList(column3Map, start));
                            column3Map.clear();
                            //初始化合并字段等级3
                            if (stringObjectMap.containsKey(MergeColumnEnum.MERGE_COLUMN3.getMergeColumn())) {
                                Object column3Obj = stringObjectMap.get(MergeColumnEnum.MERGE_COLUMN3.getMergeColumn());
                                column3Map.put(column3Obj, 1);
                            }
                        }
                    }

                } else {
                    if (firstBool) {
                        //说明第一次
                        firstBool = false;
                    } else {
                        //说明某一个合并字段等级结束 也是新的合并字段等级开始
                        //开始处理数据
                        //1,处理合并column1Map 的数据
                        column1List.addAll(getMergeParamList(column1Map, start));
                        //2,处理合并column1Map 的数据
                        column2List.addAll(getMergeParamList(column2Map, start));
                        //3,处理合并column1Map 的数据
                        column3List.addAll(getMergeParamList(column3Map, start));
                        //4,清空所有的Map
                        column1Map.clear();
                        column2Map.clear();
                        column3Map.clear();
                    }
                    //初始化map
                    column1Map.put(column1Obj, 1);
                    if (stringObjectMap.containsKey(MergeColumnEnum.MERGE_COLUMN2.getMergeColumn())) {
                        Object column2Obj = stringObjectMap.get(MergeColumnEnum.MERGE_COLUMN2.getMergeColumn());
                        column2Map.put(column2Obj, 1);
                    }
                    if (stringObjectMap.containsKey(MergeColumnEnum.MERGE_COLUMN3.getMergeColumn())) {
                        Object column3Obj = stringObjectMap.get(MergeColumnEnum.MERGE_COLUMN3.getMergeColumn());
                        column3Map.put(column3Obj, 1);
                    }
                }
            }
        }
        //1,处理合并column1Map 的数据
        column1List.addAll(getMergeParamList(column1Map, start + 1));
        //2,处理合并column1Map 的数据
        column2List.addAll(getMergeParamList(column2Map, start + 1));
        //3,处理合并column1Map 的数据
        column3List.addAll(getMergeParamList(column3Map, start + 1));

        map.put("0", column1List);
        map.put("1", column2List);
        map.put("2", column3List);

        return map;

    }

    private List<MergeParam> getMergeParamList(Map<Object, Integer> columnMap, int end) {
        List<MergeParam> mergeParamList = new ArrayList<>();
        if (MapUtil.isEmpty(columnMap)) {
            return mergeParamList;
        }
        int sum = 0;
        Set<Map.Entry<Object, Integer>> en = columnMap.entrySet();
        for (Map.Entry<Object, Integer> entry : en) {
            sum += entry.getValue();
        }
        int start = end - sum;
        for (Map.Entry<Object, Integer> entry : en) {
            if (entry.getValue() > 1) {
                MergeParam mergeParam = new MergeParam();
                mergeParam.setStart(start);
                mergeParam.setEnd(start + entry.getValue() - 1);
                start = start + entry.getValue();
                mergeParamList.add(mergeParam);
            } else {
                start++;
            }
        }
        return mergeParamList;
    }

测试数据

用的pg数据库
Mapper

public interface DataDbMapper {

     List<Map<String,Object>> getMap();
}

xml

<mapper namespace="com.yueyang.demo1.mapper.DataDbMapper">

    <select id="getMap" resultType="java.util.Map">
       select *
        from t_module_test
        order by sort asc
    </select>
</mapper>

数据

CREATE TABLE "public"."t_module_test" (
  "id" serial4,
  "column1" varchar(50) ,
  "column2" varchar(50) ,
  "column3" varchar(50) ,
  "date" varchar(50) ,
  "value" varchar(50) ,
  "sort" int8

)
;
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (1, '范围1', '范围1-1', '范围1-2', '今天', '12.11', 1);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (3, '范围1', '范围1-1', '范围1-2-1', '今天', '12.11', 3);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (4, '范围1', '范围1-1', '范围1-2-1', '今天', '12.11', 4);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (5, '范围1', '范围1-2', '范围1-2-2', '今天', '12.11', 5);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (6, '范围1', '范围1-2', '范围1-2-2', '今天', '12.11', 6);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (7, '范围1', '范围1-2', '范围1-2-2', '今天', '12.11', 7);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (8, '范围1', '范围1-2', '范围1-2-2', '今天', '12.11', 8);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (25, '范围2', '范围2-1', '范围2-2', '今天', '12.11', 9);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (26, '范围2', '范围2-1', '范围2-2-1', '今天', '12.11', 10);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (27, '范围2', '范围2-1', '范围2-2-1', '今天', '12.11', 11);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (28, '范围2', '范围2-1', '范围2-2-1', '今天', '12.11', 12);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (29, '范围2', '范围2-2', '范围2-2-2', '今天', '12.11', 13);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (30, '范围2', '范围2-2', '范围2-2-2', '今天', '12.11', 14);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (31, '范围2', '范围2-2', '范围2-2-2', '今天', '12.11', 15);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (32, '范围2', '范围2-2', '范围2-2-2', '今天', '12.11', 16);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (33, '范围3', '范围3-1', '范围3-2', '今天', '12.11', 17);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (34, '范围3', '范围3-1', '范围3-2-1', '今天', '12.11', 18);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (35, '范围3', '范围3-1', '范围3-2-1', '今天', '12.11', 19);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (36, '范围3', '范围3-1', '范围3-2-1', '今天', '12.11', 20);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (37, '范围3', '范围3-2', '范围3-2-2', '今天', '12.11', 21);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (38, '范围3', '范围3-2', '范围3-2-2', '今天', '12.11', 22);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (39, '范围3', '范围3-2', '范围3-2-2', '今天', '12.11', 23);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (40, '范围3', '范围3-2', '范围3-2-2', '今天', '12.11', 24);
INSERT INTO "public"."t_module_test"("id", "column1", "column2", "column3", "date", "value", "sort") VALUES (2, '范围1', '范围1-1', '范围1-2', '今天', '12.11', 2);

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
好的,您可以使用Java中的ZipOutputStream类来实现压缩多个Excel文件。以下是一个简单的示例代码: ```java import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Table; import com.alibaba.excel.support.ExcelTypeEnum; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import java.io.*; import java.util.ArrayList; import java.util.List; public class ExportExcel { public static void main(String[] args) throws IOException { // 创建多个Excel文件 List<File> fileList = createExcelFiles(); // 创建压缩包文件 File zipFile = new File("excel_files.zip"); ZipArchiveOutputStream zipOutputStream = new ZipArchiveOutputStream(zipFile); zipOutputStream.setMethod(ZipArchiveOutputStream.DEFLATED); // 将多个Excel文件压缩压缩包中 for (File file : fileList) { ZipArchiveEntry entry = new ZipArchiveEntry(file.getName()); entry.setSize(file.length()); zipOutputStream.putArchiveEntry(entry); FileInputStream fis = new FileInputStream(file); byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer)) > 0) { zipOutputStream.write(buffer, 0, len); } fis.close(); zipOutputStream.closeArchiveEntry(); } // 关闭ZipOutputStream流 zipOutputStream.finish(); zipOutputStream.close(); // 删除临时Excel文件 for (File file : fileList) { file.delete(); } } private static List<File> createExcelFiles() throws FileNotFoundException { List<File> fileList = new ArrayList<>(); for (int i = 1; i <= 3; i++) { // 创建Excel文件 File file = new File("excel_" + i + ".xlsx"); OutputStream out = new FileOutputStream(file); // EasyExcel导出数据 ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX); Sheet sheet = new Sheet(1, 0); sheet.setSheetName("Sheet1"); Table table = new Table(1); List<List<String>> data = new ArrayList<>(); for (int j = 1; j <= 10; j++) { List<String> row = new ArrayList<>(); row.add("Data" + j); data.add(row); } table.setData(data); writer.write0(table, sheet); writer.finish(); // 添加Excel文件到列表中 fileList.add(file); } return fileList; } } ``` 在上面的代码中,我们首先创建了3个Excel文件,然后将它们压缩到一个名为“excel\_files.zip”的压缩包中。最后,我们删除了临时的Excel文件。注意,我们使用了Apache Commons Compress库来实现压缩操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大道至简@EveryDay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值