java eazyexcel 实现excel的动态多级联动下拉列表(1)使用名称管理器+INDIRECT函数

这篇具有很好参考价值的文章主要介绍了java eazyexcel 实现excel的动态多级联动下拉列表(1)使用名称管理器+INDIRECT函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

原理

  1. 将数据源放到一个新建的隐藏的sheet中
  2. 将选项的子选项的对应字典设置到名称管理器中(名称是当前选项的内容,值是他对应的子菜单的单元格范围,在1里面的sheet中)
  3. 子菜单的数据根据INDIRECT函数去左边那个单元格获取内容,根据内容去名称管理器中获取字典的key,也就是子菜单的单元格范围
  4. 使用方式只需要构建CascadeCellBO对象即可,定义级联初始位置和行数,还有选项列表nameCascadeList,他的结构很简单就是name和子nameCascadeList。代码会自动扫描出最深的子菜单层数,根据这个层数构建下拉的个数

优缺点

优点

选项的个数和内容的个数不限制

缺点

  1. 因为excel的名称管理器的名称有很多限制比如不支持特殊字符、不支持括号、不能数字开头等等,所以选项的内容也会有这些限制
  2. 因为excel的名称管理器的名称不能相同,所有如果有两个相同二级菜单在不同的一级菜单中,那这两个二级菜单的三级菜单会是一样的

总之使用名称管理器+INDIRECT函数实现的级联下拉列表,只能做一些简单的数据,如果想克服那些缺点,需要用另一种方式,请看下篇文章

代码


import lombok.Data;

import java.util.List;

/**
 * @date 2024-01-19 21:05
 */
@Data
public class CascadeCellBO {

    /**
     * 初始的行
     */
    private int rowIndex;

    /**
     * 初始的列
     */
    private int colIndex;

    /**
     * 行数
     */
    private int rowNum;

    /**
     * 选项
     */
    private List<NameCascadeBO> nameCascadeList;
}
import lombok.Data;

import java.util.List;

/**
 * @date 2024-01-20 10:26
 */
@Data
public class NameCascadeBO {
    /**
     * 名称
     */
    private String name;

    /**
     * 子选项
     */
    private List<NameCascadeBO> nameCascadeList;
}

import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import lombok.Data;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

@Data
public class CascadeWriteHandler implements SheetWriteHandler {

    private final String dataSourceName;

    private final CascadeCellBO cascadeCellBO;

    public CascadeWriteHandler(CascadeCellBO cascadeCellBO) {
        this.cascadeCellBO = cascadeCellBO;
        this.dataSourceName = "dataSource" + System.currentTimeMillis();
    }

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

    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        //获取工作簿
        Sheet sheet = writeSheetHolder.getSheet();
        Workbook book = writeWorkbookHolder.getWorkbook();
        //创建一个专门用来存放地区信息的隐藏sheet页
        //因此不能在现实页之前创建,否则无法隐藏。
        Sheet hideSheet = book.createSheet(dataSourceName);
        book.setSheetHidden(book.getSheetIndex(hideSheet), true);
        // 将具体的数据写入到每一行中,每行的第一个单元格为父级区域的值,后面是子区域。
        List<NameCascadeBO> nameCascadeList = cascadeCellBO.getNameCascadeList();
        if (nameCascadeList == null || nameCascadeList.isEmpty()) {
            return;
        }

        Row row = hideSheet.createRow(0);
        IntStream.range(0, nameCascadeList.size()).forEach(i ->
                row.createCell(i).setCellValue(nameCascadeList.get(i).getName()));

        // 大类规则
        int colIndex = cascadeCellBO.getColIndex();
        int firstRowIndex = cascadeCellBO.getRowIndex();
        int lastRowIndex = firstRowIndex + cascadeCellBO.getRowNum();

        ///开始设置(大类小类)下拉框
        DataValidationHelper dvHelper = sheet.getDataValidationHelper();
        CellRangeAddressList expRangeAddressList = new CellRangeAddressList(firstRowIndex, lastRowIndex, colIndex, colIndex);
        String bigEndCol = colIndex2Str(nameCascadeList.size());
        DataValidationConstraint bigFormula = dvHelper.createFormulaListConstraint("=" + dataSourceName + "!$A$1:$" + bigEndCol + "$1");
        setValidation(sheet, dvHelper, bigFormula, expRangeAddressList, "提示", "你输入的值未在备选列表中,请下拉选择合适的值");

        // 小类规则(各单元格按个设置)
        // "INDIRECT($A$" + 2 + ")" 表示规则数据会从名称管理器中获取key与单元格 A2 值相同的数据,如果A2是浙江省,那么此处就是浙江省下面的市
        // 为了让每个单元格的公式能动态适应,使用循环挨个给公式。
        // 循环几次,就有几个单元格生效,次数要和上面的大类影响行数一一对应,要不然最后几个没对上的单元格实现不了级联
        AtomicInteger rowId = new AtomicInteger(1);
        buildName(book, hideSheet, nameCascadeList, rowId);
        int maxLevel = getMaxLevel(nameCascadeList, 0);
        for (int num = 1; num < maxLevel; num++) {
            String start = colIndex2Str(colIndex + num);
            String preStart = "$" + start + "$";
            for (int i = firstRowIndex; i <= lastRowIndex; i++) {
                CellRangeAddressList rangeAddressList = new CellRangeAddressList(i, i, colIndex + num, colIndex + num);
                DataValidationConstraint formula = dvHelper.createFormulaListConstraint("INDIRECT(" + preStart + (i + 1) + ")");
                setValidation(sheet, dvHelper, formula, rangeAddressList, "提示", "你输入的值未在备选列表中,请下拉选择合适的值");
            }
        }
    }

    // 添加名称管理器
    private void buildName(Workbook book, Sheet hideSheet, List<NameCascadeBO> nameCascadeList, AtomicInteger rowId) {
        Optional.ofNullable(nameCascadeList).ifPresent(l -> l.forEach(nameCascadeBO -> {
            List<NameCascadeBO> childList = nameCascadeBO.getNameCascadeList();
            if (childList != null && !childList.isEmpty()) {
                Row row = hideSheet.createRow(rowId.getAndIncrement());
                row.createCell(0).setCellValue(nameCascadeBO.getName());
                IntStream.range(0, childList.size()).forEach(c ->
                        row.createCell(c + 1).setCellValue(childList.get(c).getName()));
                // 添加名称管理器
                String endCol = colIndex2Str(1 + childList.size());
                String range = "$B$" + rowId.get() + ":$" + endCol + "$" + rowId.get();

                Name name = book.createName();
                name.setNameName(nameCascadeBO.getName());
                name.setRefersToFormula(dataSourceName + "!" + range);
                buildName(book, hideSheet, childList, rowId);
            }
        }));
    }

    private int getMaxLevel(List<NameCascadeBO> nameCascadeList, int preLevel) {
        int curLevel = preLevel + 1;
        int maxLevel = curLevel;
        for (NameCascadeBO nameCascadeBO : nameCascadeList) {
            List<NameCascadeBO> childList = nameCascadeBO.getNameCascadeList();
            if (childList != null && !childList.isEmpty()) {
                int level = getMaxLevel(childList, curLevel);
                maxLevel = Math.max(level, maxLevel);
            }
        }
        return maxLevel;
    }

    /**
     * 设置验证规则
     *
     * @param sheet       sheet对象
     * @param helper      验证助手
     * @param constraint  createExplicitListConstraint
     * @param addressList 验证位置对象
     * @param msgHead     错误提示头
     * @param msgContext  错误提示内容
     */
    private void setValidation(Sheet sheet, DataValidationHelper helper, DataValidationConstraint constraint, CellRangeAddressList addressList, String msgHead, String msgContext) {
        DataValidation dataValidation = helper.createValidation(constraint, addressList);
        dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP);
        dataValidation.setShowErrorBox(true);
        dataValidation.setSuppressDropDownArrow(true);
        dataValidation.createErrorBox(msgHead, msgContext);
        sheet.addValidationData(dataValidation);
    }

    public static String colIndex2Str(int column) {
        if (column <= 0) {
            return null;
        }
        String columnStr = "";
        column--;
        do {
            if (columnStr.length() > 0) {
                column--;
            }
            columnStr = ((char) (column % 26 + (int) 'A')) + columnStr;
            column = (int) ((column - column % 26) / 26);
        } while (column > 0);
        return columnStr;
    }
}

使用

public static void main(String[] args) {
        List<List<String>> header = new ArrayList<>();
        header.add(Arrays.asList( "sc2"));
        header.add(Arrays.asList( "sc3"));
        int colIndex = header.size() - 1;
        List<NameCascadeBO> nameCascadeList = new ArrayList<>();
        NameCascadeBO nameCascadeBO = new NameCascadeBO();
        nameCascadeBO.setName("第一层1");

        List<NameCascadeBO> nameCascadeList2 = new ArrayList<>();
        NameCascadeBO nameCascadeBO2 = new NameCascadeBO();
        nameCascadeBO2.setName("第二层11");

        List<NameCascadeBO> nameCascadeList3 = new ArrayList<>();
        IntStream.range(0, 400).forEach(i -> {
            NameCascadeBO nameCascadeBO3 = new NameCascadeBO();
            nameCascadeBO3.setName("第三层11" + i);
            nameCascadeList3.add(nameCascadeBO3);
        });

        nameCascadeBO2.setNameCascadeList(nameCascadeList3);
        nameCascadeList2.add(nameCascadeBO2);

        nameCascadeBO2 = new NameCascadeBO();
        nameCascadeBO2.setName("第二层12");
        nameCascadeList2.add(nameCascadeBO2);

        nameCascadeBO.setNameCascadeList(nameCascadeList2);
        nameCascadeList.add(nameCascadeBO);

        nameCascadeBO = new NameCascadeBO();
        nameCascadeBO.setName("第一层2");

        nameCascadeList2 = new ArrayList<>();
        nameCascadeBO2 = new NameCascadeBO();
        nameCascadeBO2.setName("第二层21");
        nameCascadeList2.add(nameCascadeBO2);

        nameCascadeBO2 = new NameCascadeBO();
        nameCascadeBO2.setName("第二层22");
        nameCascadeList2.add(nameCascadeBO2);

        nameCascadeBO.setNameCascadeList(nameCascadeList2);
        nameCascadeList.add(nameCascadeBO);

        IntStream.range(2, 200).forEach(i -> {
            NameCascadeBO item = new NameCascadeBO();
            item.setName("第一层" + i);
            nameCascadeList.add(item);
        });


        CascadeCellBO cascadeCellBO = new CascadeCellBO();
        cascadeCellBO.setRowIndex(2);
        cascadeCellBO.setRowNum(10);
        cascadeCellBO.setColIndex(colIndex);
        cascadeCellBO.setNameCascadeList(nameCascadeList);
        CascadeWriteHandler cascadeWriteHandler = new CascadeWriteHandler(cascadeCellBO);

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        EasyExcelFactory.write(outputStream).head(header)
                .registerWriteHandler(cascadeWriteHandler)
                .sheet("导入信息").doWrite(new ArrayList<>());

        FileUtils.save2File("/Users/admin/aa/导入模板.xlsx", outputStream.toByteArray());
    }

java eazyexcel 实现excel的动态多级联动下拉列表(1)使用名称管理器+INDIRECT函数,excel

java eazyexcel 实现excel的动态多级联动下拉列表(1)使用名称管理器+INDIRECT函数,excel

java eazyexcel 实现excel的动态多级联动下拉列表(1)使用名称管理器+INDIRECT函数,excel

java eazyexcel 实现excel的动态多级联动下拉列表(1)使用名称管理器+INDIRECT函数,excel文章来源地址https://www.toymoban.com/news/detail-814266.html

到了这里,关于java eazyexcel 实现excel的动态多级联动下拉列表(1)使用名称管理器+INDIRECT函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端框架Layui实现动态树效果(书籍管理系统左侧下拉列表)

    目录 一、前言 1.什么是树形菜单 2.树形菜单的使用场景 二、案例实现 1.需求分析 2.前期准备工作 ①导入依赖 ②工具类 BaseDao(通用增删改查) BuildTree(完成平级数据到父子级的转换) ResponseUtil(将数据转换成json格式进行回显) ③编写实体 3.dao层编写 4.servlet层编写 5.jsp页面搭

    2024年02月13日
    浏览(26)
  • java poi实现Excel多级表头导出

    最近碰到一个导出,比较繁琐,也查询了许多博客,在其中一篇博客的基础上修改,实现了最终想要的效果。话不多说,直接上效果图 1.主代码: 2.合并单元格 3.设置表头单元格的宽度 4.填充数据(注:我这里的数据格式是ListMapString, Object类型,可以根据自己的实际情况来封

    2024年02月03日
    浏览(35)
  • EasyExcel+POI制作带有有效性校验及下拉联动的Excel模板

    最近在做一个CRM系统的人员销售目标导入的相关需求,需要将销售人员的目标导入到系统中,就要求在Excel导入模板中 填写销售人员Id 和销售人员姓名。在使用的时候,这是一个易错的点,因为这两个字段交给了使用者去自由填写的话,是很容易填错的。除了文字本身填多填

    2024年02月11日
    浏览(28)
  • POI实现Excel省市区三级联动java实现

    2003版Excel 2007版Excel 时间校验2003版 数据校验2007版

    2024年02月06日
    浏览(56)
  • java poi生成excel折线图、柱状图、饼图、动态列表

    实现效果   测试类 实体类  工具类 完整代码地址:https://gitee.com/Szw99/create-excel.git

    2024年02月13日
    浏览(31)
  • vue实现多个下拉框联动(二)

    在Vue3的组件中,定义多个下拉框的数据和选中的值。例如: 在模板中,使用 v-model 指令绑定下拉框的选中值,并使用 @change 事件监听下拉框的值变化。例如: 在Vue3组件的方法中,编写处理下拉框值变化的逻辑。例如:

    2024年02月21日
    浏览(23)
  • Vue实现select下拉框二级联动数据后台获取

    一、二级联动在vue中实现selected的二级联动取其实很简单,可以使用select下拉框的表单改变事件。  @change在表单内容发生改变时出发方法。然后在下面的methods中声明方法,通过this.form.ks获取到当前下拉框的数据。  然后调用后两级访问数据库的方法,获取到联动的数据,添加

    2024年02月16日
    浏览(30)
  • 【vue组件】使用element-ui 实现三级联动下拉选择

    实现的思路是第一个下拉选择在选择了选项后将该选项的信息传递到接口请求下一个选项的内容,依次类推 然后在清除了上一级选择的选项后要将其次级和子孙级的选项都清除(包括选择里的列表内容) 下面看具体代码: 效果图:

    2024年02月11日
    浏览(45)
  • <Java导出Excel> 1.0 Java实现Excel动态模板导出

    思路: 1,先创建动态模板(必须要在数据库建一张表,可随时修改模板) 例如: 建表语句: 模板中的字段脚本: 2,编写一个查询接口:返回一个List map 注意:order by id 根据表中字段:id排序的作用是控制导出的EXCEL表中字段列的顺序; mapper.xml层: mapper接口层: serviceIm

    2024年02月12日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包