[alibaba/easyexcel]生成Excel文件时无报错信息,打开文件提示“部分内容有问题”

2024-05-24 177 views
9

触发场景描述 参照demo中的CustomSheetWriteHandler,生成包含下拉框的Excel文件,下拉框中数据包含有符号时,生成的Excel打开报错,提示:部分内容有问题。 从数据中去掉包含有特殊符号的两条数据后,再次生成的文件可以正常打开; 触发Bug的代码

   // 测试用的数据为:"经济型:1 勿动","大众(测试)"

提示的异常或者没有达到的效果 image

回答

3

windows中不存在这个情况,能提供一下mac的excel版本吗?

5

我拿官网demo测试了下,没有发现问题 image 同上,可能是excel版本的问题, 我之前实验的时候碰到过文件打不开的情况是因为我build出来的writer没有调用finish()

3

windows中不存在这个情况,能提供一下mac的excel版本吗?

1、MAC下的office版本是16.30(19101301),我找了个windows电脑看这个文件,同样是打不开;

新问题

2、我调整了下数据,去掉了一些包含特殊符号的数据,生成的文件可以正常打开了,但是将依赖的版本从2.0.5升级到2.1.1之后,同样数据生成的文件又出现同样的问题;

下面是2.1.1版本生成的异常文件如下,文件的大小比正常生成的小很多:

信息导入模板.xlsx

要下载的是一个空的模板文件,所以write的时候是个null,代码如下:

// 导出操作
EasyExcel.write(MuscleapeExcelUtil.getOutputStream(fileName, response), Model.class)
                .registerWriteHandler(writeHandler)
                .sheet("导入模板")
                .doWrite(null);
/**
 * MuscleapeExcelUtil.getOutputStream     
 * 导出文件时为Writer生成OutputStream
*/
public static OutputStream getOutputStream(String fileName, HttpServletResponse response) {
    try {
        fileName = new String(fileName.getBytes(), "ISO-8859-1");
        response.addHeader("Content-Disposition", "filename=" + fileName);
        return response.getOutputStream();
    } catch (IOException e) {
        throw new ExcelGenerateException("创建文件失败!");
    }
}
1

我拿官网demo测试了下,没有发现问题 image 同上,可能是excel版本的问题, 我之前实验的时候碰到过文件打不开的情况是因为我build出来的writer没有调用finish()

因为需求是生成一个空的模板文件,所以write的时候是个null,代码如下:

// 导出操作
EasyExcel.write(MuscleapeExcelUtil.getOutputStream(fileName, response), Model.class)
                .registerWriteHandler(writeHandler)
                .sheet("导入模板")
                .doWrite(null);
/**
 * MuscleapeExcelUtil.getOutputStream     
 * 导出文件时为Writer生成OutputStream
*/
public static OutputStream getOutputStream(String fileName, HttpServletResponse response) {
    try {
        fileName = new String(fileName.getBytes(), "ISO-8859-1");
        response.addHeader("Content-Disposition", "filename=" + fileName);
        return response.getOutputStream();
    } catch (IOException e) {
        throw new ExcelGenerateException("创建文件失败!");
    }
}
7

你上面发的这个文件是正常的,我window版本可以打开,只不过是个完全空的文件,有可能是版本不同(我的是wps2019),导致无法打开,可能需要调查一下。 另外,如果只想输出空白表头,推荐将null替换成空集合,例如Collections.emptyList()

        // 导出操作
        EasyExcel.write(fileName, Model.class)
                .registerWriteHandler(new CustomSheetWriteHandler())
                .sheet("导入模板")
                .doWrite(Collections.emptyList());

输出null时,在内部做了空判断,没有继续执行输出逻辑,源代码: com.alibaba.excel.write.ExcelBuilderImpl#addContent(java.util.List, com.alibaba.excel.write.metadata.WriteSheet, com.alibaba.excel.write.metadata.WriteTable)

    @Override
    public void addContent(List data, WriteSheet writeSheet, WriteTable writeTable) {
        try {
            if (data == null) {
                return;
            }
            context.currentSheet(writeSheet, WriteTypeEnum.ADD);
            context.currentTable(writeTable);
            if (excelWriteAddExecutor == null) {
                excelWriteAddExecutor = new ExcelWriteAddExecutor(context);
            }
            excelWriteAddExecutor.add(data);
        } catch (RuntimeException e) {
            finish();
            throw e;
        } catch (Throwable e) {
            finish();
            throw new ExcelGenerateException(e);
        }
    }

也许是没有添加sheet页之类的导致的(猜测)

8

你上面发的这个文件是正常的,我window版本可以打开,只不过是个完全空的文件,有可能是版本不同(我的是wps2019),导致无法打开,可能需要调查一下。 另外,如果只想输出空白表头,推荐将null替换成空集合,例如Collections.emptyList()

        // 导出操作
        EasyExcel.write(fileName, Model.class)
                .registerWriteHandler(new CustomSheetWriteHandler())
                .sheet("导入模板")
                .doWrite(Collections.emptyList());

输出null时,在内部做了空判断,没有继续执行输出逻辑,源代码: com.alibaba.excel.write.ExcelBuilderImpl#addContent(java.util.List, com.alibaba.excel.write.metadata.WriteSheet, com.alibaba.excel.write.metadata.WriteTable)

    @Override
    public void addContent(List data, WriteSheet writeSheet, WriteTable writeTable) {
        try {
            if (data == null) {
                return;
            }
            context.currentSheet(writeSheet, WriteTypeEnum.ADD);
            context.currentTable(writeTable);
            if (excelWriteAddExecutor == null) {
                excelWriteAddExecutor = new ExcelWriteAddExecutor(context);
            }
            excelWriteAddExecutor.add(data);
        } catch (RuntimeException e) {
            finish();
            throw e;
        } catch (Throwable e) {
            finish();
            throw new ExcelGenerateException(e);
        }
    }

也许是没有添加sheet页之类的导致的(猜测)

针对您指出的这几处,我认为是这样的

1、生成的异常文件,用WPS可以打开,但是文件也是异常的状态,还是想排查下为啥会生成异常的文件; 2、从目前测试的情况来看,doWrite()中直接指定null并不会影响文件生成,在2.0.5版本中也是用的null数据,不包含带符号的数据时生成的文件是可以正常打开的,这样应该是可以排除使用null导致文件异常的情况;

我的下拉框数据生成方式如下

1、在SheetWriteHandler的实现类中,添加String[]类型的属性及SheetWriteHandler实现类的构造函数; 2、在开始导出文件,调用SheetWriteHandler实现的时候,new一个SheetWriteHandler的实现类,并通过构造函数将多个下拉框需要的数据传进去;

/**
* SheetWriteHandler的实现类
*/
public class TemplateSheetWriteHandler implements SheetWriteHandler {

/**
* 下拉框选项1
*/
private String[] theFirst;

/**
* 下拉框选项2
*/
private String[] theSecond;

// 构造函数
public TemplateSheetWriteHandler(String[] theFirst,String[] theSecond) {
        this.theFirst = theFirst;
        this.theSecond = theSecond;
}

@Override
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {

}

@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
    LOGGER.info("第{}个Sheet写入成功。", writeSheetHolder.getSheetNo());
    // 区间设置 第一列第一行和第二行的数据。由于第一行是头,所以第一、二行的数据实际上是第二三行
    DataValidationHelper helper = writeSheetHolder.getSheet().getDataValidationHelper();
    // theFirst
    if (ArrayUtils.isNotEmpty(theFirst)) {
    CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 1000, 0, 0);
    DataValidationConstraint constraint = helper.createExplicitListConstraint(theFirst);
    DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);
    writeSheetHolder.getSheet().addValidationData(dataValidation);
    }
    // theSecond
    if (ArrayUtils.isNotEmpty(theSecond)) {
    CellRangeAddressList cellRangeAddressList2 = new CellRangeAddressList(1, 1000, 3, 3);
    DataValidationConstraint constraint2 = helper.createExplicitListConstraint(theSecond);
    DataValidation dataValidation2 = helper.createValidation(constraint2, cellRangeAddressList2);
    writeSheetHolder.getSheet().addValidationData(dataValidation2);
    }
}

}
TemplateSheetWriteHandler writeHandler = new TemplateSheetWriteHandler(busyType,operationCity);

// 导出操作
EasyExcel.write(MuscleapeExcelUtil.getOutputStream(fileName, response), Model.class)
                .registerWriteHandler(writeHandler)
                .sheet("导入模板")
                .doWrite(null);
6

经验证,下拉框中文本长度超过255导致该问题