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

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

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

来看整体的项目目录

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

一、主流程代码

java 复制代码
@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方式,从而就解决了个数限制的问题。
java 复制代码
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

java 复制代码
@Data
@AllArgsConstructor
public class TemplateOneVO {

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

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

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

SheetOneVO

java 复制代码
@Data
@AllArgsConstructor
public class SheetOneVO {

    private String key;
}
相关推荐
南 阳13 小时前
Python从入门到精通day66
开发语言·python
好家伙VCC13 小时前
【无标题】
java
十八旬14 小时前
快速安装ClaudeCode完整指南
开发语言·windows·python·claude
前进的李工14 小时前
EXPLAIN输出格式全解析:JSON、TREE与可视化
开发语言·数据库·mysql·性能优化·explain
小碗羊肉14 小时前
【JavaWeb | 第十一篇】文件上传(本地&阿里云OSS)
java·阿里云·servlet
吾疾唯君医14 小时前
Java SpringBoot集成积木报表实操记录
java·spring boot·spring·导出excel·积木报表·数据文件下载
Byron Loong14 小时前
【c++】为什么有了dll和.h,还需要包含lib
java·开发语言·c++
独隅15 小时前
CodeX + Visual Studio Code 联动的全面指南
开发语言·php
坚果派·白晓明15 小时前
【鸿蒙PC三方库移植适配框架解读系列】第一篇:Lycium C/C++ 三方库适配 — 概述与环境配置
c语言·开发语言·c++·harmonyos·开源鸿蒙·三方库·c/c++三方库
hexu_blog15 小时前
vue+java实现图片批量压缩
java·前端·vue.js