Java Excel 多级菜单联动原理与实现(可扩展)

Java Excel级联菜单实现(可扩展)

为什么要写这篇文章呢,因为看到了有人在提问如何用Java做Excel的级联菜单效果。帖子详情:http://spring4all.com/forum-post/575
我之前也遇到过同样的场景,当时查了很多文档才搞定,为了让更多人可以直接使用代码,节省时间,所以决定写这篇文章。

实现效果

先上效果图,这里演示我做了三级下拉菜单的联动,不过我实现的版本可以支持任意级菜单的联动
在这里插入图片描述

实现原理介绍

名称管理器

Excel中有名称管理器的概念,什么意思呢。可以简单理解为,一个名称对应一组数据序列,举个例子,一个省会对映多个市,省名则是名称管理器的名字,对应的数据序列则是相关的市级城市名。

在创建下拉关系对映规则时,需要先根据数据的对映关系,创建所有名称管理器,然后再用数据有效性绑定名称管理器的名字就行了。
在这里插入图片描述
可以在公式->名称管理器内查看我这边创建的名称管理器和对映关系。

数据有效性

名称管理器创建好了,怎么使用呢?这就要用到Excel的数据有效性了。
你可以任意选中一个单元格,在菜单栏上点击数据->有效性
在这里插入图片描述
在数据有效性内设置如下
在这里插入图片描述
来源参数说明
=INDIRECT() :Excel内置函数,可以返回单元格的值引用
dataSheet:数据页的名称
$A$1:数据页的单元格位置
$A$1 是什么值呢,其实就是province
在这里插入图片描述
还记得名称管理器的province对应的数据序列吗,会被引用到这个单元格上,于是效果如下
在这里插入图片描述
好了,基本原理就是这样,接下来我们看下怎么使用代码生成

设计与约定

易使用

只需要用到两个注解,分别是ExcelFile、ExcelValidation
ExcelFile代表需要生成文件
目前Excel是在本地创建的,不过可以根据我的源码修改成上传到服务器,如果你需要帮助,可以给我留言
ExcelValidation是打在字段上的,用来标注字段是否需要生成校验。
目前获取数据源的的方式比较单一,只支持静态无参方法,如果你的项目整合了Spring,也可以改从Bean方法内获取数据,如果你需要帮助,可以给我留言

低入侵

你可以选择copy源码或者打jar包的方式来使用,只需要在Excel实体对象上标注注解即可

约定

  1. 如果数据集返回的是List,代表是单独的、无依赖的列
  2. 如果数据集返回的是Map,key是依赖列的名称,value是key所对应的数据

小试牛刀

我的项目结构
excel-example是例子,准备的一些数据
excel-extend是具体的实现
![在这里插入图片描述](https://img-blog.csdnimg.cn/0ecd87d063cb4fe8b16fac7e253776cd.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAeGltdV9zdW5ueQ==,size_20,color_FFFFFF,t_70,g_se,x_16

首先我在com.excel.service.ExcelExampleService准备了数据列表
queryProvinceList,获取省列表
queryMunicipalityList,获取市列表,Map的Key是所属的省
queryDistrictList,获取区列表,Map的Key是所属的市

public class ExcelExampleService {
   
   

    public static List<String> queryProvinceList() {
   
   
        return Arrays.asList("浙江省", "湖南省", "贵州省");
    }

    public static Map<String, List<String>> queryMunicipalityList() {
   
   
        Map<String, List<String>> map = new HashMap<>(4);
        map.put("浙江省", Arrays.asList("杭州市", "温州市", "宁波市"));
        map.put("湖南省", Arrays.asList("长沙市", "邵阳市", "常德市"));
        map.put("贵州省", Arrays.asList("贵阳市", "遵义市", "安顺市"));
        return map;
    }

    public static Map<String, List<String>> queryDistrictList() {
   
   
        Map<String, List<String>> map = new HashMap<>(8);
        map.put("杭州市", Arrays.asList("上城区", "下城区", "萧山区"));
        map.put("温州市", Arrays.asList("鹿城区", "龙湾区", "瓯海区", "洞头区"));
        map.put("长沙市", Arrays.asList("芙蓉区", "天心区", "岳麓区"));
        map.put("邵阳市", Arrays.asList("双清区", "大祥区", "北塔区"));
        map.put("贵阳市", Arrays.asList("南明区", "云岩区", "花溪区"));
        return map;
    }

}

然后配置DTO

import com.excel.annotation.ExcelFile;
import com.excel.annotation.ExcelValidation;
import lombok.Data;

/**
 * @author ximu
 * @date 2022/4/6
 * @description
 */
@ExcelFile(fileHeadTemplate = "province|municipality|district", fileMappingTemplate = "province=所属省|municipality=所属市|district=所属区",
        datasheetHidden = false, enableDataValidation = true)
@Data
public class ExcelExportDTO {
   
   

    /**
     * 所属省
     */
    @ExcelValidation(datasourceMethod = "com.excel.service.ExcelExampleService.queryProvinceList")
    private String province;

    /**
     * 所属市
     */
    @ExcelValidation(datasourceMethod = "com.excel.service.ExcelExampleService.queryMunicipalityList", beforeFieldName = "province")
    private String municipality;

    /**
     * 所属区
     */
    @ExcelValidation(datasourceMethod = "com.excel.service.ExcelExampleService.queryDistrictList", beforeFieldName = "municipality")
    private String district;

}

启动项目,创建Excel

public class T_Main {
   
   

    public static void main(String[] args) throws IOException {
   
   
        ExcelExportDTO excelExportDTO = new ExcelExportDTO();
        String excel = ExcelUtil.createExcel(Arrays.asList(excelExportDTO));
        System.out.println(excel);
    }

}

创建成功后,sheet1可以正常的选择下拉菜单
你会发现还有一页数据页,可以隐藏起来
使用 ExcelFile 注解属性 datasheetHidden 配置
默认是 true 隐藏的
在这里插入图片描述
如果用户随意输入值的话,是可以强制校验的
在这里插入图片描述
通过 ExcelFile 注解 showErrorBox 属性控制

实现代码

注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author ximu
 * @date 2021/8/29
 * @description 标记类为一个Excel文件
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({
   
   ElementType.TYPE}
评论 18
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值