Java导出Excel模板实现级联下拉框

1、依赖导入

项目使用jdk8版本,apache的导入导出工具类。

<dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.2</version>
</dependency>

2、代码实现

话不多说,直接上代码

package com.test;

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;

import java.io.FileOutputStream;
import java.util.*;


/**
 * Excel数据联动
 *
 * @author wuming
 * @date 2023-09-14
 **/
public class ExcelTest {

    /**
     * 影响最大行数
     */
    private static final int XLS_MAX_ROW = 60000;


    public static void main(String[] args) {
        //省数据
        List<String> provinceList = Arrays.asList("江苏省", "河南省", "天津市", "北京市");
        //父子类关系
        Map<String, List<String>> childrenMap = new HashMap<>();
        childrenMap.put("江苏省", Arrays.asList("苏州市", "南通市", "无锡市", "常州市"));
        childrenMap.put("河南省", Arrays.asList("新乡市", "开封市", "洛阳市"));
        childrenMap.put("天津市", Arrays.asList("南开区", "和平区"));
        childrenMap.put("北京市", Arrays.asList("海淀区", "朝阳区"));

        // 性别
        List<String> sexList = new ArrayList<>();
        sexList.add("男");
        sexList.add("女");
        sexList.add("未知");

        exportHSSFTemplate(sexList, provinceList, childrenMap);
    }


    /**
     * 导出模板
     *
     * @param sexList  性别列表
     * @param provinceList  省级列表
     * @param cityMap  市级下拉列表(Map中省级对应市级列表)
     */
    public static void exportHSSFTemplate(List<String> sexList, List<String> provinceList, Map<String, List<String>> cityMap) {

        String[] titleList = new String[]{"姓名", "性别", "所在省", "所在市"};

        //创建工作簿对象
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet sheet = workbook.createSheet("sheet");
        sheet.setDefaultColumnWidth(18);
        HSSFRow row = sheet.createRow(0);
        HSSFCellStyle style = getStyle(workbook);

        for (int i = 0; i < titleList.length; i++) {
            String title = titleList[i];
            HSSFCell cell = row.createCell(i);
            cell.setCellValue(title);
            cell.setCellStyle(style);
            cell.setCellType(CellType.STRING);
        }
        // 创建隐藏目录
        createHideSheetHSSF(workbook, provinceList, cityMap);

        // 性别下拉
        DVConstraint sexConstraint = DVConstraint.createExplicitListConstraint(sexList.toArray(new String[]{}));
        CellRangeAddressList sexRangeAddressList = new CellRangeAddressList(1, XLS_MAX_ROW, 1, 1);
        DataValidation sexDataValidation = new HSSFDataValidation(sexRangeAddressList, sexConstraint);
        sexDataValidation.createErrorBox("error", "请选择正确的性别");
        sheet.addValidationData(sexDataValidation);


        // 如果省市区的excel位置不是如上titleList中的位置,需要变更则需要INDIRECT中所在的列名称
        // 省份规则
        DVConstraint provConstraint = DVConstraint.createExplicitListConstraint(provinceList.toArray(new String[]{}));
        CellRangeAddressList provRangeAddressList = new CellRangeAddressList(1, XLS_MAX_ROW, 2, 2);
        DataValidation provinceDataValidation = new HSSFDataValidation(provRangeAddressList, provConstraint);
        provinceDataValidation.createErrorBox("error", "请选择正确的省份");
        sheet.addValidationData(provinceDataValidation);

        // 市级下拉规则
        CellRangeAddressList cityRange = new CellRangeAddressList(1, XLS_MAX_ROW, 3, 3);
        DataValidation cityValidation = new HSSFDataValidation(cityRange, DVConstraint.createFormulaListConstraint("INDIRECT($C1)"));
        cityValidation.createErrorBox("error", "请选择正确的市级");
        sheet.addValidationData(cityValidation);

        try {
            FileOutputStream fileOut = new FileOutputStream("d://excel_template.xls");
            workbook.write(fileOut);
            fileOut.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建隐藏页
     *
     * @param workbook    sheet页
     * @param provinceList  级联父级
     * @param cityMap 级联子级
     */
    public static void createHideSheetHSSF(HSSFWorkbook workbook, List<String> provinceList, Map<String, List<String>> cityMap) {
        //创建一个专门用来存放地区信息的隐藏sheet页
        HSSFSheet hideSheet = workbook.createSheet("city");

        int rowId = 0;
        // 设置第1行,存省的信息
        Row provinceRow = hideSheet.createRow(rowId++);
        for (int i = 0; i < provinceList.size(); i++) {
            Cell provinceCell = provinceRow.createCell(i);
            provinceCell.setCellValue(provinceList.get(i));
        }
        // 将具体的数据写入到每一行中,行开头为父级区域,后面是子区域。
        if ( !cityMap.isEmpty() ) {
            for (String province : provinceList) {
                // 获取省份信息对应的市级信息列表
                List<String> cityList = cityMap.get(province);
                Row prow = hideSheet.createRow(rowId++);
                prow.createCell(0).setCellValue(province);
                for (int j = 0; j < cityList.size(); j++) {
                    Cell cell = prow.createCell(j + 1);
                    cell.setCellValue(cityList.get(j));
                }
                // 添加名称管理器
                String range = getRange(1, rowId, cityList.size());
                Name name = workbook.createName();
                // key不可重复
                name.setNameName(province);
                String formula = "city!" + range;
                name.setRefersToFormula(formula);
            }
        }
        workbook.setSheetHidden(1, true);
    }

    /**
     * 样式
     *
     * @param workbook sheet页
     * @return HSSFCellStyle 返回样式
     */
    private static HSSFCellStyle getStyle(HSSFWorkbook workbook) {
        HSSFCellStyle cellStyle = workbook.createCellStyle();
        // 水平居中
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        // 垂直居中
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        // 自动换行
        //cellStyle.setWrapText(true);

        HSSFFont font = workbook.createFont();
        // 设置字体名称
        font.setFontName("宋体");
        // 字体大小
        font.setFontHeightInPoints((short) 12);
        font.setBold(true);
        cellStyle.setFont(font);
        return cellStyle;
    }


    /**
     * 计算formula
     *
     * @param offset   偏移量,如果给0,表示从A列开始,1,就是从B列
     * @param rowId    第几行
     * @param colCount 一共多少列
     * @return 如果给入参 1,1,10. 表示从B1-K1。最终返回 $B$1:$K$1
     */
    public static String getRange(int offset, int rowId, int colCount) {
        char start = (char) ('A' + offset);
        if (colCount <= 25) {
            char end = (char) (start + colCount - 1);
            return "$" + start + "$" + rowId + ":$" + end + "$" + rowId;
        } else {
            char endPrefix = 'A';
            char endSuffix = 'A';
            if ((colCount - 25) / 26 == 0 || colCount == 51) {// 26-51之间,包括边界(仅两次字母表计算)
                if ((colCount - 25) % 26 == 0) {// 边界值
                    endSuffix = (char) ('A' + 25);
                } else {
                    endSuffix = (char) ('A' + (colCount - 25) % 26 - 1);
                }
            } else {// 51以上
                if ((colCount - 25) % 26 == 0) {
                    endSuffix = (char) ('A' + 25);
                    endPrefix = (char) (endPrefix + (colCount - 25) / 26 - 1);
                } else {
                    endSuffix = (char) ('A' + (colCount - 25) % 26 - 1);
                    endPrefix = (char) (endPrefix + (colCount - 25) / 26);
                }
            }
            return "$" + start + "$" + rowId + ":$" + endPrefix + endSuffix + "$" + rowId;
        }
    }

}

3、级联参数说明

代码粘贴执行后,可能会注意到这一行代码

CellRangeAddressList cityRange = new CellRangeAddressList(1, XLS_MAX_ROW, 3, 3);
        DataValidation cityValidation = new HSSFDataValidation(cityRange, DVConstraint.createFormulaListConstraint("INDIRECT($C1)"));
        cityValidation.createErrorBox("error", "请选择正确的市级");
        sheet.addValidationData(cityValidation);

这里的INDIRECT($C1)参数较为重要,$C1表示省份所在列,正如下图,因为其在C1框中及C列,因此根据自己需要,修改这里的列属位置。

4、效果显示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到性别是单一的下拉框,而所在省所在市是存在级联关系的,选择了省,才可以选择省份下对应的市级信息。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值