EasyExcel能否导出xlsm文件,后端代码如何做单元行设置分组折叠展开操作。

最近遇到一个导出Excel问题。
客户导出的xlsm文件无法保存,校验发现提示特殊字符超过一定数量。

img

img

我尝试把内容中一些单元格内的菱形替换掉之后,保存成功。(所以我怀疑是特殊字符的原因)

img

后来我又导出少量的数据,进行编辑后,是可以成功保存的。(到此可以确定是特殊字符的原因)

和业务商量是否可以不使用特殊字符。被否定了!

然后我尝试用EasyExcel导出。所以在尝试的过程中遇到两个问题,没办法解决了。
1,EasyExcel 能否支持导出xlsm文件。(因为客户需要可以使用宏的Excel文件)
2,EasyExcel 导出后端如何做对单元行的分组折叠展开的设置(以前POI会使用sheet.groupRow(int var1, int var2);sheet.setRowGroupCollapsed(int var1, boolean var2);来进行设置)

POI设置单元行的分组折叠展开后的效果图

img

还望各位不吝解答,万分感谢。

https://ask.csdn.net/questions/7612086?spm=1005.2026.3001.5635&utm_medium=distribute.pc_relevant_ask_down.none-task-ask-2~default~OPENSEARCH~Rate-2.pc_feed_download_top3ask&depth_1-utm_source=distribute.pc_relevant_ask_down.none-task-ask-2~default~OPENSEARCH~Rate-2.pc_feed_download_top3ask


package com.myFirstSpring.test; 
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
 
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;
import com.alibaba.excel.support.ExcelTypeEnum;
 
/** 
 * @author tqf
 * @version 创建时间:2020-4-1 下午2:21:08 
 * 类说明: 阿里开源(EasyExcel)---生成导出EXCEL文件  Soeasy
 */
public class ExcelMain {
    
    public static void main(String[] args) {
        try {
            long time = System.currentTimeMillis();//获取当前系统时间(毫秒)
            writeExcelOneSheetOnceWrite();
            System.out.println(System.currentTimeMillis()-time+"毫秒");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    /**
     * 针对较少的记录数(20W以内大概)可以调用该方法一次性查出然后写入到EXCEL的一个SHEET中
     * 注意: 一次性查询出来的记录数量不宜过大,不会内存溢出即可。
     *
     * @throws IOException
     */
    public static void writeExcelOneSheetOnceWrite() throws IOException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 生成EXCEL并指定输出路径
        //在本地新建一个文件夹 用于保存文件
        File file1=new File("D:\\测试生成Excel文件");  
        if(!file1.exists()){//如果文件夹不存在  
            file1.mkdir();//创建文件夹  
        }
        OutputStream out = new FileOutputStream(""+file1+"\\测试SHEET.xls");
        ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLS);
        
        for (int j = 0; j < 2; j++) { //这个地方是写入了2个SHEET文件里面
             // 设置SHEET
            Sheet sheet = new Sheet(j, 0);
            sheet.setSheetName("测试sheet"+j);
            Table table;
            // 设置标题
            if(j == 0){
                 table = new Table(1);
                 List<List<String>> titles = new ArrayList<List<String>>();
                 titles.add(Arrays.asList("用户ID"));
                 titles.add(Arrays.asList("名称"));
                 titles.add(Arrays.asList("年龄"));
                 titles.add(Arrays.asList("生日"));
                 table.setHead(titles);
            }else{
                 table = new Table(2);
                 List<List<String>> titles = new ArrayList<List<String>>();
                 titles.add(Arrays.asList("用户ID1"));
                 titles.add(Arrays.asList("名称1"));
                 titles.add(Arrays.asList("年龄1"));
                 titles.add(Arrays.asList("生日1"));
                 titles.add(Arrays.asList("多个字段"));
                 table.setHead(titles);
            }
            // 查询数据导出即可 比如说一次性总共查询出1000条数据   模拟数据插入
            List<List<String>> userList = new ArrayList<List<String>>();
            for (int i = 0; i < 1000; i++) {
                userList.add(Arrays.asList("ID_" + i, "小谭" + i, String.valueOf(i), format.format(new Date())));
            }
            writer.write0(userList, sheet, table);
        }
        writer.finish();
        out.close();
    }
 /**
     * 针对几百万的记录数可以调用该方法分多批次查出然后写入到EXCEL的多个SHEET中
     * 注意:
     * perSheetRowCount % pageSize要能整除  为了简洁,非整除这块不做处理
     * 每次查询出来的记录数量不宜过大,根据内存大小设置合理的每次查询记录数,不会内存溢出即可。
     *
     * @throws IOException
     */
    public static void writeExcelMoreSheetMoreWrite() throws IOException {
 
        // 生成EXCEL并指定输出路径
        OutputStream out = new FileOutputStream("F:\\temp\\withoutHead3.xls");
        ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLS);
        
        File file = new File("F:\\测试生成Excel文件");
        if(!file.exists()){
            file.mkdir();
        }
        // 设置SHEET名称
        String sheetName = "测试SHEET";
 
        // 设置标题
        Table table = new Table(1);
        List<List<String>> titles = new ArrayList<List<String>>();
        titles.add(Arrays.asList("用户ID"));
        titles.add(Arrays.asList("名称"));
        titles.add(Arrays.asList("年龄"));
        titles.add(Arrays.asList("生日"));
        table.setHead(titles);
 
        // 模拟分批查询:总记录数250条,每个SHEET存100条,每次查询20条  则生成3个SHEET,前俩个SHEET查询次数为5, 最后一个SHEET查询次数为3 最后一次写的记录数是10
        // 注:该版本为了较少数据判断的复杂度,暂时perSheetRowCount要能够整除pageSize, 不去做过多处理  合理分配查询数据量大小不会内存溢出即可。
        Integer totalRowCount = 250;
        Integer perSheetRowCount = 100;
        Integer pageSize = 20;
        Integer sheetCount = totalRowCount % perSheetRowCount == 0 ? (totalRowCount / perSheetRowCount) : (totalRowCount / perSheetRowCount + 1);
        Integer previousSheetWriteCount = perSheetRowCount / pageSize;
        Integer lastSheetWriteCount = totalRowCount % perSheetRowCount == 0 ?
                previousSheetWriteCount :
                (totalRowCount % perSheetRowCount % pageSize == 0 ? totalRowCount % perSheetRowCount / pageSize : (totalRowCount % perSheetRowCount / pageSize + 1));
 
        for (int i = 0; i < sheetCount; i++) {
 
            // 创建SHEET
            Sheet sheet = new Sheet(i, 0);
            sheet.setSheetName(sheetName + i);
 
            if (i < sheetCount - 1) {
 
                // 前2个SHEET, 每个SHEET查5次 每次查20条 每个SHEET写满100行  2个SHEET合计200行  实用环境:参数: currentPage: j+1 + previousSheetWriteCount*i, pageSize: pageSize
                for (int j = 0; j < previousSheetWriteCount; j++) {
                    List<List<String>> userList = new ArrayList<List<String>>();
                    for (int k = 0; k < 20; k++) {
                        userList.add(Arrays.asList("ID_" + Math.random(), "小明", String.valueOf(Math.random()), new Date().toString()));
                    }
                    writer.write0(userList, sheet, table);
                }
 
            } else if (i == sheetCount - 1) {
 
                // 最后一个SHEET 实用环境不需要将最后一次分开,合成一个即可, 参数为: currentPage = i+1;  pageSize = pageSize
                for (int j = 0; j < lastSheetWriteCount; j++) {
 
                    // 前俩次查询 每次查询20条
                    if (j < lastSheetWriteCount - 1) {
 
                        List<List<String>> userList = new ArrayList<List<String>>();
                        for (int k = 0; k < 20; k++) {
                            userList.add(Arrays.asList("ID_" + Math.random(), "小明", String.valueOf(Math.random()), new Date().toString()));
                        }
                        writer.write0(userList, sheet, table);
 
                    } else if (j == lastSheetWriteCount - 1) {
 
                        // 最后一次查询 将剩余的10条查询出来
                        List<List<String>> userList = new ArrayList<List<String>>();
                        Integer lastWriteRowCount = totalRowCount - (sheetCount - 1) * perSheetRowCount - (lastSheetWriteCount - 1) * pageSize;
                        for (int k = 0; k < lastWriteRowCount; k++) {
                            userList.add(Arrays.asList("ID_" + Math.random(), "小明1", String.valueOf(Math.random()), new Date().toString()));
                        }
                        writer.write0(userList, sheet, table);
 
                    }
                }
            }
        }
 
        writer.finish();
    }
}