EasyExcel导出模板实现下拉选(解决下拉超过50个限制)


先来看看最终实现效果,如果效果是你想要的,再看看实现逻辑。

在这里插入图片描述



EasyExcel本身是支持设置下拉校验的,但有个问题,一旦下拉数据超过50个左右的时候就无法正常展示,当然,现在这个问题得到了解决。


来看整体的项目目录

在这里插入图片描述

如果你之前使用过EasyExcel那上面主流程代码你将会很熟悉,下拉选相较于之前的导出只是多注册了一个 Handler。


一、主流程代码

@RestController
@RequestMapping("/one")
public class OneController {

    // 测试数据构建
    private static List<String> countryList = Arrays.asList("中国","美国","俄罗斯","德国","日本");
    private static List<String> cityList = Arrays.asList("深圳","广州","上海","北京","纽约","莫斯科","东京");
    private static Map<String, List> dropDownData = new HashMap<>(2);
    private static List<SheetOneVO> cityEntityList = new ArrayList<>(cityList.size());
    static {
        dropDownData.put("country", countryList);
        dropDownData.put("city", cityList);

        for (String item : cityList) {
            cityEntityList.add(new SheetOneVO(item));
        }
    }



    @GetMapping("/kk-one")
    public void one(HttpServletResponse response) throws Exception {

        // 通用内容设置
        String fileName = URLEncoder.encode("templateOne.xlsx",CharEncoding.UTF_8);
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding(CharEncoding.UTF_8);
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName);

        // 构建模板数据
        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
        WriteSheet writeSheet = EasyExcel
                .writerSheet(0, "one")
                .registerWriteHandler(new XdxCellWriteHandler(dropDownData))
                .head(TemplateOneVO.class)
                .build();

        WriteSheet citySheet = EasyExcel
                .writerSheet(1, "city")
                .head(SheetOneVO.class)
                .needHead(false)
                .build();

        excelWriter.write(Arrays.asList(new TemplateOneVO("张三","美国", "胡佛")), writeSheet)
                .write(cityEntityList, citySheet).
                finish();
    }
}

二、处理器代码


  1. 这个handler重写了单元格拦截器,在遍历表头的时候,设置下拉选。
  2. 正常是超过50个下拉才会出问题,这里懒得造那么多数据所以设置了一个LIMIT,超过它就会换成联动sheet方式,从而就解决了个数限制的问题。
public class XdxCellWriteHandler implements CellWriteHandler {

    /**
     * 超过 LIMIT 的大小就使用 sheet关联下拉,否则直接设置下拉
     */
    private static final Integer LIMIT = 6;

    private Map<String, List> dropDownData;

    public XdxCellWriteHandler(Map<String, List> dropDownData) {
        this.dropDownData = dropDownData;
    }

    /**
     * 设置下拉框数据
     * @param writeSheetHolder
     * @param key 当前列名
     * @param rowIndex 行号
     * @param columnIndex 列号
     */
    private void setSelectDataList(WriteSheetHolder writeSheetHolder, String key, int rowIndex, int columnIndex) {
        if (dropDownData.get(key) == null) {
            return;
        }

        Sheet sheet = writeSheetHolder.getSheet();
        DataValidationHelper helper = sheet.getDataValidationHelper();

        // 设置下拉列表的行: 首行,末行,首列,末列
        CellRangeAddressList rangeList = new CellRangeAddressList(rowIndex, 50000, columnIndex, columnIndex);
        // 设置下拉列表的值
        DataValidationConstraint constraint;
        if (dropDownData.get(key).size() < LIMIT) {
            // 直接设置下拉选
            constraint = helper.createExplicitListConstraint((String[]) dropDownData.get(key).toArray(new String[0]));
        } else {
            // 联动到另外一个 sheet
            constraint = helper.createFormulaListConstraint(key+ "!$A$1:$A$" + dropDownData.get(key).size());
        }

        // 设置约束
        DataValidation validation = helper.createValidation(constraint, rangeList);
        // 阻止输入非下拉选项的值
        validation.setErrorStyle(DataValidation.ErrorStyle.STOP);
        validation.setShowErrorBox(true);
        validation.setSuppressDropDownArrow(true);
        validation.createErrorBox("提示", "请输入下拉选项中的内容");
        sheet.addValidationData(validation);
    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
                                 List<WriteCellData<?>> cellDataList, Cell cell, Head head,
                                 Integer relativeRowIndex, Boolean isHead) {
                                 
        // 设置隐藏 sheet
        WriteSheet writeSheet = writeSheetHolder.getWriteSheet();
        if (writeSheet.getSheetNo() > 0) {
            Workbook workbook = writeSheetHolder.getParentWriteWorkbookHolder().getWorkbook();
            workbook.setSheetHidden(writeSheet.getSheetNo(), true);
            return;
        }                         
                                 
        if (!isHead) {
            //设置value下拉框
            setSelectDataList(writeSheetHolder, head.getFieldName(), cell.getRowIndex(), cell.getColumnIndex());
        }
    }
}

三、两个VO


TemplateOneVO

@Data
@AllArgsConstructor
public class TemplateOneVO {

    @ExcelProperty("姓名")
    private String name;

    @ExcelProperty("国家")
    private String country;

    @ExcelProperty("城市")
    private String city;
}

SheetOneVO

@Data
@AllArgsConstructor
public class SheetOneVO {

    private String key;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值