java-poi操作Excel,实现二级级联动态生成

本文介绍了一个Java程序,该程序能够动态地为Excel工作簿生成带有数据验证下拉列表的模板。通过从数据库获取有害信息类型并填充到隐藏的工作表中,程序实现了下拉列表的选择项动态更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

直接贴代码:

package com.jinhui.reportingcentre.baseinfo.typecatalog.controller;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.DVConstraint;
import org.apache.poi.hssf.usermodel.HSSFDataValidation;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.jinhui.core.BaseAction;
import com.jinhui.reportingcentre.Constants;
import com.jinhui.reportingcentre.admin.system.service.ISysParamService;
import com.jinhui.reportingcentre.baseinfo.typecatalog.domain.TypeCatalogBean;
import com.jinhui.reportingcentre.baseinfo.typecatalog.service.ITypeCatalogService;
import com.jinhui.reportingcentre.utils.DeleteFileUtil;
import com.jinhui.reportingcentre.utils.HttpSessionUtil;

/**
 * 有害信息类型维护
 * @author bin
 */
@Controller
@RequestMapping("/typecatalog")
public class TypeAction extends BaseAction {
    private static Logger logger = Logger.getLogger(TypeAction.class);
    @Autowired
    private ITypeCatalogService typeCatalogService;
    
    private String EXCEL_HIDE_SHEET_NAME = "excelhidesheetname";
    private String HIDE_SHEET_NAME_BIGTYPE = "bigTypeList"; 
    private HashMap map = new HashMap();//危害小类
    public static final String ERROR = "error";

    @Autowired
    private ISysParamService sysParamService; // 系统参数service
    
    /**
     * 修改excel导入模板
     */
    @SuppressWarnings("unchecked")
    @RequestMapping("/updateExcel")
    public String updateExcel(@RequestParam("type") String type,@RequestParam("reporttype") String reporttype,HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        PrintWriter pw = response.getWriter();
        
        boolean flag = false;
        try {
            flag = rewriteExcelTempAtEmp("temp/templates/no_excelDome_web.xls",
                            "temp/templates/匿名批量导入.xls", 3, "C");
            if(flag){
                pw.print("1");
            }else{
                pw.print("2");
            }
        } catch (Exception e) {
            e.printStackTrace();
            pw.print("2");
        } finally {
            pw.flush();
            pw.close();
            return null;
        }
    }

    //private  bigList;//危害大类
    /**
     * 动态生成危害大类的excel模板
     * 
     * @throws IOException
     */
    
    
    /**
     * 动态生成大类小类级联的excel模板
     * @param excelStart 未添加级联的原始Excel模板路径
     * @param excelStop    生成最终Excel的保存路径
     * @param RowNum 生成在Excel的第几列
     * @param Rowletter 生成在Excel的列名(A,B,C...)
     * @return
     * @throws IOException
     */
    private boolean rewriteExcelTempAtEmp(String excelStart, String excelStop,
            int RowNum, String Rowletter) throws IOException {
        boolean flag = false;
        Workbook workbook = null;
        try {
            String[] bigList = bigTypeList();
            // 读取默认模板Excel文件
            String path = HttpSessionUtil.getRootPath() + excelStart;
            workbook = readWorkBook(path);

            if (EXCEL_HIDE_SHEET_NAME.equals(workbook
                    .getSheetIndex(EXCEL_HIDE_SHEET_NAME))) {
                workbook.removeSheetAt(workbook
                        .getSheetIndex(EXCEL_HIDE_SHEET_NAME)); // 删除隐藏表
            }
            
            Sheet hideInfoSheet = workbook.createSheet(EXCEL_HIDE_SHEET_NAME);// 隐藏一些信息
            // 在隐藏页设置选择信息
            // 第二行设置危害大类
            Row bigNameRow = hideInfoSheet.createRow(0);
            creatRow(bigNameRow, bigList);
            // 以下行设置危害小类列表
            for (int i = 0; i < map.size(); i++) {
                Row smallNameRow = hideInfoSheet.createRow(i + 1);
                String[] Stringlist = (String[]) map.get("bigList" + i);
                creatRow(smallNameRow, Stringlist);
            }
            // 名称管理
            // 第一行设置大类信息
            creatExcelNameList(workbook, HIDE_SHEET_NAME_BIGTYPE, 1,
                    bigList.length, false);
            // 以后动态大小设置大类对应的小类列表

            for (int i = 0; i < bigList.length; i++) {
                String[] Stringlist = (String[]) map.get("bigList" + i);
                creatExcelNameList(workbook, bigList[i], i + 2,
                        Stringlist.length, true);
            }

            // 设置隐藏页标志
            workbook.setSheetHidden(
                    workbook.getSheetIndex(EXCEL_HIDE_SHEET_NAME), true);

            // 添加数据
            setDataValidation(workbook, RowNum, Rowletter);

            String newPath = HttpSessionUtil.getRootPath()+excelStop;

            /**** 删除旧的模板 ******/
            DeleteFileUtil.deleteFile(newPath);

            /**** 生成新的模板 ******/
            // 由于POI打开读取文件后再保存时bug问题, 只能重新定义一个新的Excel写入数据
            createExcel(workbook, newPath);
            
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
            workbook.close();
            flag = false;
        }
        return flag;
    }

    /**
     * 读取服务器上面的上传的excel文件
     * 
     * @param path
     * @return
     */
    public static Workbook readWorkBook(String path) {
        Workbook wb = null;
        try {
            wb = WorkbookFactory.create(new File(path));
        } catch (InvalidFormatException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return wb;
    }

    /**
     * 创建一列数据
     * 
     * @param currentRow
     * @param textList
     */
    private static void creatRow(Row currentRow, String[] textList) {
        if (textList != null && textList.length > 0) {
            int i = 0;
            for (String cellValue : textList) {
                Cell userNameLableCell = currentRow.createCell(i++);
                userNameLableCell.setCellValue(cellValue);
            }
        }
    }

    /**
     * 添加数据验证选项
     * 
     * @param sheet
     */
    public void setDataValidation(Workbook wb, int RowNum, String Rowletter) {
        int sheetIndex = wb.getNumberOfSheets();
        if (sheetIndex > 0) {
            for (int i = 0; i < sheetIndex; i++) {
                Sheet sheet = wb.getSheetAt(i);
                if (!EXCEL_HIDE_SHEET_NAME.equals(sheet.getSheetName())) {
                    DataValidation data_validation_list = null;
                    // 危害大类选项添加验证数据
                    for (int a = 4; a < 581; a++) {
                        // data_validation_list =
                        // getDataValidationByFormula(HIDE_SHEET_NAME_BIGTYPE,a,8);
                        data_validation_list = getDataValidationByFormula(
                                HIDE_SHEET_NAME_BIGTYPE, a, RowNum);
                        sheet.addValidationData(data_validation_list);
                        // 危害小类选项添加验证数据
                        // data_validation_list =
                        // getDataValidationByFormula("INDIRECT(H"+a+")",a,9);
                        data_validation_list = getDataValidationByFormula(
                                "INDIRECT($" + Rowletter +"$"+ a + ")", a,
                                RowNum + 1);
                        sheet.addValidationData(data_validation_list);
                    }
                }
            }
        }
    }

    /**
     * 使用已定义的数据源方式设置一个数据验证
     * 
     * @param formulaString
     * @param naturalRowIndex
     * @param naturalColumnIndex
     * @return
     */
    private static DataValidation getDataValidationByFormula(
            String formulaString, int naturalRowIndex, int naturalColumnIndex) {
        // 加载下拉列表内容
        DVConstraint constraint = DVConstraint
                .createFormulaListConstraint(formulaString);
        // 设置数据有效性加载在哪个单元格上。
        // 四个参数分别是:起始行、终止行、起始列、终止列
        int firstRow = naturalRowIndex - 1;
        int lastRow = naturalRowIndex - 1;
        int firstCol = naturalColumnIndex - 1;
        int lastCol = naturalColumnIndex - 1;
        CellRangeAddressList regions = new CellRangeAddressList(firstRow,
                lastRow, firstCol, lastCol);
        // 数据有效性对象
        DataValidation data_validation_list = new HSSFDataValidation(regions,
                constraint);
        // //设置输入信息提示信息
        // data_validation_list.createPromptBox("下拉选择提示","请使用下拉方式选择合适的值!");
        // //设置输入错误提示信息
        // data_validation_list.createErrorBox("选择错误提示","你输入的值未在备选列表中,请下拉选择合适的值!");
        return data_validation_list;
    }

    /**
     * 创建一个名称
     * 
     * @param workbook
     */
    private void creatExcelNameList(Workbook workbook, String nameCode,
            int order, int size, boolean cascadeFlag) {
        Name name;
        name = workbook.createName();
        name.setNameName(nameCode);
        name.setRefersToFormula(EXCEL_HIDE_SHEET_NAME + "!"
                + creatExcelNameList(order, size, cascadeFlag));
    }

    /**
     * 名称数据行列计算表达式
     * 
     * @param workbook
     */
    private static String creatExcelNameList(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;
            }
        }
    }

    /**
     * 根据路径创建Excel
     * 
     * @author duanqm
     * @param workbook
     * @param path
     */
    public static void createExcel(Workbook workbook, String path) {
        System.setProperty("sun.jnu.encoding","utf-8");
        FileOutputStream fileOut = null;
        try {
            fileOut = new FileOutputStream(path);
            workbook.write(fileOut);
        } catch (Exception e) {
            // logger.error("Error create excel: ", e.getMessage());
        } finally {
            try {
                if (fileOut != null) {
                    fileOut.close();
                    workbook.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取所有可显示的危害大类,组成数组
     * 
     * @return
     */
    public String[] bigTypeList() {
        String[] List = new String[] {};

        TypeCatalogBean bigBean = new TypeCatalogBean();
        bigBean.setParentCodeId(Constants.CODEKIND_TYPECATALOG);
        bigBean.setIsdisplay(0);
        List<TypeCatalogBean> bigList = typeCatalogService.findNoNetwork(bigBean);

        //去掉侵权类0105
        for (int i = 0; i < bigList.size(); i++) {
            TypeCatalogBean bean = bigList.get(i);
            if (bean.getItemId().equals("0105")) {
                bigList.remove(bean);
                break;
            }
        }
        
        if (bigList.size() > 0) {
            String[] blist = new String[bigList.size()];
            for (int i = 0; i < bigList.size(); i++) {
                blist[i] = bigList.get(i).getItemName();// 危害大类存入数组

                // 获取子类
                TypeCatalogBean smallBean = new TypeCatalogBean();
                smallBean.setParentCodeId(bigList.get(i).getItemId());
                List<TypeCatalogBean> smallList = typeCatalogService
                        .queryForList(smallBean);

                if (smallList.size() > 0) {
                    // 存放子类
                    String[] slist = new String[smallList.size() + 1];
                    slist[0] = bigList.get(i).getItemName();// 危害大类先放进去
                    for (int j = 0; j < smallList.size(); j++) {
                        slist[j + 1] = smallList.get(j).getItemName();// 危害子类存入数组
                    }
                    map.put("bigList" + i, slist);
                } else {
                    String[] slist = new String[1];
                    slist[0] = bigList.get(i).getItemName();// 危害大类先放进去
                    map.put("bigList" + i, slist);
                }
            }
            List = blist;
        }
        return List;
    }
    
}
 

### 如何在 Excel实现级联下拉列表 #### 使用数据验证功能创建静级联下拉列表 通过Excel内置的数据验证功能可以轻松建立简单的级联下拉菜单。先在一个工作表内准备两个区域作为源数据,比如A列放置主要类别(如国家),B列及其右侧若干列分别对应不同主类别的子项(如城市)。之后,在另一位置利用INDIRECT函数配合数据验证来构建依赖于前者选择结果的次选项。 对于第一个下拉列表而言,仅需指定固定范围即可;而第二个动变化的部分,则要基于前面所选值关联至相应辅助列区间完成设置[^4]。 ```excel =INDIRECT(A2) ``` 此公式假设首栏位于单元格`A2`处选取了某国名,那么上述表达式将会指引向预设好的该国所属都市名单地址。 #### 利用VBA宏编写自动化脚本生成复杂逻辑下的级联效果 针对更高的应用场景或是希望减少手动配置的工作量时,可以通过录制并编辑Visual Basic for Applications (VBA) 宏代码的方式来自定义更为灵活多变的选择关系链路。下面给出了一段基础示范性的VBA代码片段用于说明这一过程: ```vba Private Sub Worksheet_Change(ByVal Target As Range) Dim ws As Worksheet Set ws = ThisWorkbook.Sheets("Sheet1") ' 修改为实际使用的 sheet 名称 If Not Intersect(Target, ws.Range("A:A")) Is Nothing Then With ws.Range("B:B").Validation .Delete On Error Resume Next .Add Type:=xlValidateList, AlertStyle:= _ xlValidAlertStop, Operator:= _ xlBetween, Formula1:="=INDIRECT(A" & Target.Row & ")" On Error GoTo 0 End With End If End Sub ``` 这段 VBA 脚本监听 A 列的变化事件,并据此更新 B 列中的可用选项集合。每当用户更改 A 列里的某个条目后,它就会自动调整相邻右边一格可选项目的清单。 #### 借助第三方库简化开发流程 除了依靠原生特性外,还可以考虑采用像 EasyExcel 或 Apache POI 这样的开源 Java 库来进行更加复杂的业务处理,尤其是在涉及大量数据操作或者与其他系统集成的情况下显得尤为有用。这些工具提供了丰富的 API 接口支持开发者快速搭建起满足特定需求的功能模块,例如自动生成带有交互特性的报表文件等[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值