EasyExcel中使用自定义注解解决Attempting to write a row[0] in the range

自定义注解用于解决使用 easyExcel 中 手动插入数据 多列且大于255 个常用下拉选项的的时候 , 导致报错

java.lang.IllegalArgumentException: Attempting to write a row[0] in the range [0,300] that is already written to disk.

的情况.例如说

List<DropDownOptions> options = new ArrayList<>();
        options.add(new DropDownOptions(0,userService.selectUserListName()));//两行都需要用户名称数据下拉框,并且下拉内容较多的
        options.add(new DropDownOptions(3,userService.selectUserListName()));
        ExcelUtil.exportExcel(new ArrayList<>(), "联锁管理", Lsglxx.class, response,
                options);

步骤1: 添加registerWriteHandler

exportExcel(…)方法中的exportExcelExcelWriterSheetBuilder 里面添加下拉框builder.registerWriteHandler(new ExcelUserHandler());

2.添加Handler 去Handler implements SheetWriteHandler

import com.alibaba.excel.metadata.FieldCache;
import com.alibaba.excel.metadata.FieldWrapper;
import com.alibaba.excel.util.ClassUtils;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import com.ocse.provider.flowable.annotation.ExcelUserFormat;
import com.ocse.provider.flowable.utils.SpringUtils;
import com.ocse.provider.service.AuthService;
import com.ocse.provider.service.UserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class ExcelUserHandler implements SheetWriteHandler {

    /**
     * 创建sheet页前的操作
     *
     * @param writeWorkbookHolder
     * @param writeSheetHolder
     */
    @Override
    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        log.info("创建sheet之前");
    }

    /**
     * 创建sheet页后的操作
     *
     * @param writeWorkbookHolder
     * @param writeSheetHolder
     */
    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {

        log.info("第{}个Sheet写入成功。", writeSheetHolder.getSheetNo());
        DataValidationHelper helper = writeSheetHolder.getSheet().getDataValidationHelper();

       
        AuthService authService = SpringUtils.getBean(AuthService.class);
        UserInfoService userInfoService = SpringUtils.getBean(UserInfoService.class);
        List<String> collect = null;
        try {
            //常用数据的 数据来源 , 此处设置成 员工姓名-编码 例:李四-lisi
            collect = authService.findAllUserListByOrgUnitCode(userInfoService.getUserInfo().getOrgUnitCode()).stream().map(item ->
                    item.getUserName() + "-" + item.getUserCode()

            ).collect(Collectors.toList());
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 创建sheet,突破下拉框255的限制
        //获取一个workbook
        Workbook workbook = writeWorkbookHolder.getWorkbook();
        //定义sheet的名称
        String sheetName = "人员";
        //1.创建一个隐藏的sheet 名称为 人员
        Sheet proviceSheet = workbook.createSheet(sheetName);
        // 设置隐藏
        workbook.setSheetHidden(workbook.getSheetIndex(proviceSheet), true);
        for (int i = 0, length = collect.size(); i < length; i++) {
            // i:表示你开始的行数  0表示你开始的列数
            proviceSheet.createRow(i).createCell(0).setCellValue(collect.get(i));
        }
        Name category1Name = workbook.createName();
        category1Name.setNameName(sheetName);
        // $A$1:$A$N代表 以A列1行开始获取N行下拉数据
        category1Name.setRefersToFormula(sheetName + "!$A$1:$A$" + (collect.size()));
        //2.循环赋值(为了防止下拉框的行数与隐藏域的行数相对应,将隐藏域加到结束行之后)
        FieldCache fieldCache = ClassUtils.declaredFields(writeWorkbookHolder.getClazz(), writeWorkbookHolder);
        for (Map.Entry<Integer, FieldWrapper> entry : fieldCache.getSortedFieldMap().entrySet()) {
            FieldWrapper wrapper = entry.getValue();
            Field field = wrapper.getField();
            // 循环实体中的每个属性
            // 可选的下拉值
            if (field.isAnnotationPresent(ExcelUserFormat.class)) {
                // 如果指定了@ExcelUserFormat
                ExcelUserFormat format = field.getDeclaredAnnotation(ExcelUserFormat.class);
                int index = 0;
                if (format.index() == -1) {
                    index = entry.getKey();
                }else {
                    index = format.index();
                }
                //5 将刚才设置的sheet引用到你的下拉列表中
                CellRangeAddressList addressList = new CellRangeAddressList(1, collect.size(), index, index);
                DataValidationConstraint constraint8 = helper.createFormulaListConstraint(sheetName);
                DataValidation dataValidation = helper.createValidation(constraint8, addressList);

                // 数据有效性对象
                // 处理Excel兼容性问题
                if (dataValidation instanceof XSSFDataValidation) {
                    //数据校验
                    dataValidation.setSuppressDropDownArrow(true);
                    //错误提示
                    dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP);
                    dataValidation.createErrorBox("提示", "此值与单元格定义数据不一致");
                    dataValidation.setShowErrorBox(true);
                    //选定提示
                    dataValidation.createPromptBox("填写说明:", "填写内容格式为:人员名称-人员编号,其他将导致导入异常");
                    dataValidation.setShowPromptBox(true);
                    proviceSheet.addValidationData(dataValidation);
                } else {
                    dataValidation.setSuppressDropDownArrow(false);
                }
                writeSheetHolder.getSheet().addValidationData(dataValidation);
            }
        }
    }
}

3.实现自定义注解

package com.ocse.provider.flowable.annotation;


import java.lang.annotation.*;

/**
 * 需要给哪一列设置用户下拉框,加上该注解即可
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ExcelUserFormat {

    /**
     * 需要给哪一列设置下拉框,设置列的数字即可
     */
    int index() default -1;

}

4.使用示例

@TableName(value = "t_lsglxx")
@Data
@ExcelIgnoreUnannotated
public class Lsglxx implements Serializable {
......
    /**
     * 负责人
     */
    @TableField(value = "fzr")
    @ExcelProperty(value = "负责人(统一身份账号)",index = 3)
    @ExcelUserFormat
    private String fzr;
    
        /**
     * 申请人
     */
    @TableField(value = "sqr")
    @ExcelProperty(value = "申请人(统一身份账号)",index = 17)
    @ExcelUserFormat
    private String sqr;
......
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值