使用Apache POI生成具有三级联动下拉列表的Excel文档;
具体效果图与代码如下文。

先上效果图:


开始贴代码,代码中部分测试数据不影响功能。

第一部分(核心业务处理):

此部分包含几个方面:

  1. 获取三级下拉框各列的数据;
  2. 创建每个下拉功能的名称管理器
  3. 在隐藏的sheet中生成下拉菜单所需要的row
代码如下:
/**
 * 第一部分
 * 将三个列表所有字段从数据库查询出,并生成名称管理器,存放至隐藏的sheet中
 */
private static HSSFWorkbook writePorpData() {
    int index = 1;
    HSSFWorkbook wb = new HSSFWorkbook();   //Excel工作簿创建
    wb.createSheet(DICT_SHEET_TEST);        //创建主工作表sheet
    Sheet dictDataSheet = wb.createSheet(DICT_SHEET_DATA);  //创建数据源字段sheet
    List<Province> provinceList = GetData.getProvinces();       //获取所有省份    --测试数据,不影响功能
    List<String> provinceNames = new ArrayList<String>();       //1.存放所有省份的名称
    provinceNames.add("  ");        //使下拉框有置空的选择
    //遍历每个省份
    for (Province province : provinceList) {
        String proName = province.getProvinceName();        //获取每个省份名称
        provinceNames.add(proName);
        String provinceId = province.getProvinceId();       //获取每个省份Id
        List<Area> areaList = GetData.getAreas(provinceId);     //获取每个地区    --测试数据,不影响功能
        List<String> areaNames = new ArrayList<String>();       //2.存放所有地区名称
        areaNames.add("  ");        //使下拉框有置空的选择
        //遍历每个地区
        for (Area area : areaList) {
            String areaName = area.getAreaName();
            areaNames.add(areaName);
            String areaId = area.getAreaId();
            List<City> cityList = GetData.getCities(areaId);    //获取每个城市    --测试数据,不影响功能
            List<String> cityNames = new ArrayList<String>();   //3.存放所有城市名称
            cityNames.add("  ");    //使下拉框有置空的选择
            //遍历每个城市
            for (City city : cityList) {
                String cityName = city.getCityName();
                cityNames.add(cityName);
            }
            cityNames.add(0, areaName);
            createRowData(dictDataSheet.createRow(index++),cityNames);// 3.创建城市row
            int i2 = 0;
            createExcelName(wb,cityNames.get(i2++),index,cityNames.size()-1,true);  //3.城市row,指定名称管理
        }
        areaNames.add(0, proName);
        createRowData(dictDataSheet.createRow(index++),areaNames);// 2.创建地区row
        int i1 = 0;
        createExcelName(wb,areaNames.get(i1++),index,areaNames.size()-1,true);  //2.地区row,指定名称管理
    }
    createRowData(dictDataSheet.createRow(0),provinceNames);    //  1.创建省份row,写入数据
    createExcelName(wb,DICT_MNGNAME,1,provinceNames.size()-1, false);       //1.省份row,指定名称管理
    wb.setSheetHidden(wb.getSheetIndex(DICT_SHEET_DATA), true);     //设置隐藏的sheet
    return wb;
}

第二部分:

此部分方法都是第一部分核心处理所要使用的几个函数:

  1. 创建隐藏sheet数据行的函数
  2. 创建名称管理器的函数
  3. 创建名称管理器所需要的:计算列的表达式的函数
  4. 设置数据有效性的函数
  5. 数据验证的函数
代码如下:
/**
 * 第二部分:2.1     创建隐藏sheet数据行的函数
 */
private static void createRowData(Row curRow,List<String> dataList){
    if(dataList != null && dataList.size()>0){
        int m = 0;
        for (String dataValue : dataList) {
            Cell dataCell = curRow.createCell(m++);
            dataCell.setCellValue(dataValue);
        }
    }
}
/**
 * 第二部分:2.2     创建名称管理器的函数  每一行数据创建一个
 */
private static void createExcelName(HSSFWorkbook workbook,String nameCode,int order,int size,boolean cascadeFlag){
    Name name;
    name = workbook.createName();
    name.setNameName(nameCode);
    String cellString = DICT_SHEET_DATA + "!" + createExcelNameList(order,size,cascadeFlag);
    name.setRefersToFormula(cellString);
}
/**
 * 第二部分:2.3     名称数据行列计算表达式
 */
private static String createExcelNameList(int order,int size,boolean cascadeFlag){
    char start='A';
    if(cascadeFlag){
        start = 'B';
        if(size <= 25){
            char end = (char)(start + size -1);
            return "$" + start + "$" + order + ":$" + end + "$" + order;
        }else{
            char endPrefix = 'A';
            char endSuffix = 'A';
            if((size-25)/26 == 0 || size ==51){ //26-51之间,包括边界
                if((size-25)%26 == 0){  //边界值
                    endSuffix = (char)('A' + 25);
                }else{
                    endSuffix = (char)('A' + (size-25)%26-1);
                }
            }else{  //51之上
                if((size-25)%26 == 0){
                    endSuffix = (char)('A' + 25);
                    endPrefix = (char)(endPrefix + (size-25)/26 -1);
                }else{
                    endSuffix = (char)('A' + (size-25)%26-1);
                    endPrefix = (char)(endPrefix + (size-25)/26);
                }
            }
            return "$" + start + "$" + order + ":$" + endPrefix+endSuffix + "$" + order;
        }
    }else{
        if(size<=26){
            char end = (char)(start + size -1);
            return "$" + start + "$" + order + ":$" + end + "$" + order;
        }else{
            char endPrefix = 'A';
            char endSuffix = 'A';
            if(size%26 == 0){
                endSuffix = (char)('A' + 25);
                if(size>52 && size/26>0){
                    endPrefix = (char)(endPrefix + size/26-2);
                }
            }else{
                endSuffix = (char)('A' + size%26-1);
                if(size>52 && size/26>0){
                    endPrefix = (char)(endPrefix + size/26-1);
                }
            }
            return "$" + start + "$" + order + ":$" + endPrefix+endSuffix + "$" + order;
        }
    }
}
/**
 * 第二部分:2.4 设置数据的有效性,即下拉列表的生成
 */
public static HSSFWorkbook getWorkbook(HSSFWorkbook wb, int size){
    Sheet sheet = wb.getSheet(DICT_SHEET_TEST);
    DataValidation dataValidation = null;
    for (int x = 1; x <= size+1; x++) {
        dataValidation = getDataValidation("IF($B$"+x+"=\"  \",\"  \",INDIRECT($B$"+x+"))", x, 3);
        sheet.addValidationData(dataValidation);

        dataValidation = getDataValidation("IF($C$"+x+"=\"  \",\"  \",INDIRECT($C$"+x+"))", x, 4);
        sheet.addValidationData(dataValidation);
    }
    return wb;
}
/**
 * 第二部分:2.5 数据验证
 */
@SuppressWarnings("deprecation")
private static DataValidation getDataValidation(String formulaString,int naturalRowIndex,int naturalColIndex){
    //设置数据有效性加载在哪个单元格上  四个参数:起始行、终止行、起始列、终止列
    int firstRow = naturalRowIndex-1;
    int lastRow = naturalRowIndex-1;
    int firstCol = naturalColIndex-1;
    int lastCol = naturalColIndex-1;
    CellRangeAddressList regions = new CellRangeAddressList(firstRow, lastRow, firstCol, lastCol);
    //加载下拉列表
    DVConstraint constraint = DVConstraint.createFormulaListConstraint(formulaString);
    //数据有效性对象
    DataValidation dataValidation = new HSSFDataValidation(regions, constraint);
    //设置输入信息提示信息
    dataValidation.createPromptBox("下拉提示", "请选择合适的值");
    //设置输入错误提示信息
    dataValidation.createErrorBox("非法输入", "不允许输入,请选取下拉值!");
    return dataValidation;
}

第三部分:

此部分即获得上两部处理完成后的工作簿,然后填充数据即可。

代码如下:
/**
 * 创建并生成excel文档
 */
public static void createExcelFile(){
    List<Student> studens = GetData.getStudents();      //测试数据,不影响功能
    try {
        FileOutputStream fileOutputStream = new FileOutputStream(new File(filePathName));
        HSSFWorkbook wb = writePorpData();                      // 创建工作簿
        HSSFSheet sheet = wb.getSheet(DICT_SHEET_TEST);         // 获取主工作表
        wb = getWorkbook(wb, studens.size());

        HSSFRow row = null;
        HSSFCell cell = null;
        sheet.setDefaultColumnWidth(28);
        row = sheet.createRow(0);           // 新增标题行
        cell = row.createCell(0);
        cell.setCellType(HSSFCell.CELL_TYPE_STRING);
        cell.setCellValue("学生");
        cell = row.createCell(1);
        cell.setCellType(HSSFCell.CELL_TYPE_STRING);
        cell.setCellValue("省份");
        cell = row.createCell(2);
        cell.setCellType(HSSFCell.CELL_TYPE_STRING);
        cell.setCellValue("地区");
        cell = row.createCell(3);
        cell.setCellType(HSSFCell.CELL_TYPE_STRING);
        cell.setCellValue("城市");

        int i = 1;
        for (Student stu : studens) {
            row = sheet.createRow(i);                   // 新增一行
            cell = row.createCell(0);
            cell.setCellType(HSSFCell.CELL_TYPE_STRING);
            cell.setCellValue(stu.getStudentName());    // 学生姓名
            cell = row.createCell(1);
            cell.setCellType(HSSFCell.CELL_TYPE_STRING);
            cell.setCellValue(stu.getProvince());       //省份
            cell = row.createCell(2);
            cell.setCellType(HSSFCell.CELL_TYPE_STRING);
            cell.setCellValue(stu.getArea());           // 地区
            cell = row.createCell(3);
            cell.setCellType(HSSFCell.CELL_TYPE_STRING);
            cell.setCellValue(stu.getCity());           //城市
            i++;
        }

        sheet.setColumnWidth(0,5000);//设置列宽
        sheet.setColumnWidth(1,5000);//设置列宽
        sheet.setColumnWidth(2,5000);//设置列宽
        sheet.setColumnWidth(3,5000);//设置列宽

        wb.write(fileOutputStream);             //生成文档
        fileOutputStream.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Java下使用Apache POI生成具有三级联动下拉列表的Excel文档的更多相关文章

  1. 【Java】使用Apache POI生成和解析Excel文件

    概述 Excel是我们平时工作中比较常用的用于存储二维表数据的,JAVA也可以直接对Excel进行操作,分别有jxl和poi,2种方式. HSSF is the POI Project's pure ...

  2. java用org.apache.poi包操作excel

    一.POI简介 Jakarta POI 是apache的子项目,目标是处理ole2对象.它提供了一组操纵Windows文档的Java API 目前比较成熟的是HSSF接口,处理MS Excel(97- ...

  3. Java使用poi包读取Excel文档

    项目需要解析Excel文档获取数据,就在网上找了一些资料,结合自己这次使用,写下心得: 1.maven项目需加入如下依赖: <dependency> <groupId>org. ...

  4. Java之Poi导出Excel文档

    一.Poi简介 在后台管理系统中,我们经常要做的导出操作,通常导出为Excel文档的形式,而Poi则提供了这种需要的支持. 二.Workbook/HSSFWorkbook/XSSFWorkbook 1 ...

  5. java生成excel文档

    要做一个后台自动化,要先预先生成一份文档,以下内容生成了文档 首先下载jxl.jar包,下载地址:http://download.csdn.net/detail/prstaxy/4469935 1.生 ...

  6. struts2中利用POI导出Excel文档并下载

    1.项目组负责人让我实现这个接口,因为以前做过类似的,中间并没有遇到什么太困难的事情.其他不说,先上代码: package com.tydic.eshop.action.feedback; impor ...

  7. POI 读取Excel文档中的数据——兼容Excel2003和Excel2007

    Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. HSSF - 提供读写Microsoft Exce ...

  8. Mybatis-Generator 自动生成Dao、Model、Mapping相关文档

    最近在学习mybatis,结果在写Mapping的映射文件时insert语句一直报错,于是想看看标准的映射文件是什么样.百度到Mybatis-Generator 自动生成Dao.Model.Mappi ...

  9. poi 读取使用 Strict Open XML 保存的 excel 文档

    poi 读取使用 Strict Open XML 保存的 excel 文档 某项目有一个功能需要读取 excel 报表内容,使用poi读取时报错: 具体错误为: org.apache.poi.POIX ...

随机推荐

  1. 【安卓】aidl.exe E 10744 10584 io_delegate.cpp:102] Error while creating directories: Invalid argument

    这几天在使用.aidl文件的时候eclipse的控制台总是爆出如下提示: aidl.exe E 10744 10584 io_delegate.cpp:102] Error while creatin ...

  2. 今天是JQ 的slideUp 和 slideDown 的点击事件

    先贴代码,再讲详细事件 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> & ...

  3. fastJson泛型如何转换

    引子 现在负责的业务 和 json 打交道比较多, 最近使用fastJson框架 json串转成泛型对象遇到了一个异常 : java.lang.ClassCastException 还原下场景 : 模 ...

  4. BZOJ 1898: [Zjoi2004]Swamp 沼泽鳄鱼( dp + 矩阵快速幂 )

    ----------------------------------------------------------------------- #include<cstdio> #incl ...

  5. Qt5:Qt中图片的翻转,旋转,缩放,扭曲操作

    具体用到了  mirror()  shear()  scaled() translate() rotate() 等函数函数等会儿再写 (其中  translate() 和 rotate() 俩函数组合 ...

  6. php设计模式--命名空间与自动载入

    关于命名空间: 最早的php是没有命名空间的概念的,这样不能存在相同名称的类或者函数,当项目变大了之后,产生冲突的可能性就高了,代码量也会变大,为了规划,从php5.3开始对命名空间就支持了. 说明代 ...

  7. C#中DateTime的缺陷与代替品DateTimeOffset

    C#中的DateTime在逻辑上有个非常严重的缺陷: > var d = DateTime.Now; > var d2 = d.ToUniversalTime(); > d == d ...

  8. __FILE__、__DIR__区别

    __FILE__=D:\Soft\xampp\htdocs\test\test.php __DIR__=D:\Soft\xampp\htdocs\test getcwd()=D:\Soft\xampp ...

  9. 剑指offer——python【第31题】整数1出现的次数

    题目描述 求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1.10.11.12.13因此共出现6次,但是对于后面问题他就没辙了. ...

  10. 注解Annotation实现原理与自定义注解例子

    什么是注解? 对于很多初次接触的开发者来说应该都有这个疑问?Annontation是Java5开始引入的新特征,中文名称叫注解.它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metada ...