The method and case of adding a drop-down dictionary in JAVA POI excel, as well as detailed graphic explanation and personal understanding

Scenes

Some columns in a certain sheet of the original Excel page need to add the specified dictionary drop-down, and the values ​​of these dictionaries are confirmed.

There are two ways of thinking :
1. If the given drop-down dictionary value is definite and the position of the associated original column will not change, then these data can be hard-coded in the code, which is also the simplest scenario

2. If the number of given dictionary values ​​and the position of the associated original columns will change, then it is the second more complicated scenario, with more variables and more calculations, but such codes also have stronger compatibility, but Understanding takes time.

Here I use the second, more compatible way to explain the scenes that I personally encountered in actual combat. It may take some time to understand, but once understood, it doesn't seem so complicated.

1. First, you need to understand what is the action of manually adding drop-down in Excel

For example, my first sheet and second sheet are as follows.
insert image description here
If I want to add two dictionaries in sheet2 under the title of the second and fourth columns in sheet1 , the actual operation is actually like this

  1. Select the original cell first
    insert image description here
  2. Then click Add Data Validation
    insert image description here
  3. Specify it as a sequence in the verification, and specify the source as the three boxes of Sheet2. The formula of the source does not need to be entered by hand. After clicking the icon on the right side of the source, you can drag the cursor to specify the required cell, and click OK after completion.
    insert image description here
  4. The effect is as follows
    insert image description here
    Another dictionary is also operated as above;

The implementation steps in the code are actually similar to the actual operation sequence , namely:

  1. First, create the dictionary in the specified Sheet
  2. Then the value of the formula of each dictionary needs to be calculated by ourselves, and the dictionary and formula are recorded through a custom collection
  3. Then associate the value of the formula to the specified cell column of the first Sheet through data validation

Operation example in actual code

Prerequisite: You need to understand the basic Excel operation codes, including the most basic operations of sheet, row and cell.

  1. Here I first set the name of my first sheet for storing all data as sheet1
    insert image description here
    (setDefaultColumnWidth is to set the default column width, you don’t need to set it)

  2. Set the second sheet as a dictionary sheet and I named it templateDic insert image description here
    (setDefaultColumnWidth is to set the default column width, you don’t need to set it)

  3. Then we need to sort out the dictionaries we need (assemble the data collection of all dictionaries according to our own business).

  4. Then write to this dictionary sheet. Since the row needs to be specified first when writing data to a cell, but the row needs to be created before continuing, so here my idea is to take out the item with the most dictionary value and add it to the longest dictionary value 3 (3 is added here just to be compatible with the header row of the first row and two extra rows as fault-tolerant rows) as the number of rows to be created.
    Here we can convert all the dictionary values ​​into a collection of List<String> , and then write them in
    sequence. My code is roughly as follows:

    /**
     * 获取最大的字典长度,并在sheet中创建对应长度的 row
     * @param templateDicSheet 字典sheet
     * @param list 所有字典集合
     */
    private void getCreateRowsByDicList(Sheet templateDicSheet, List<MyExcelDicModel> list) {
    
    
        Integer maxLength = 1;
        // MyExcelDicModel 为我自己定义的excel字典类,里面包含了
        for (MyExcelDicModel myExcelDicModel : list) {
    
    
        	// SourceList 为当前字典的所有字典值 List<String>
            List<String> sourceList = myExcelDicModel.getSourceList();
            if (CollectionUtils.isNotEmpty(sourceList) && sourceList.size() >= maxLength) {
    
    
                maxLength = sourceList.size();
            }
        }
        // 额外加3 容错
        maxLength += 3;

        for (Integer index = 0; index < maxLength; index++) {
    
    
             templateDicSheet.createRow(index);
        }
    }

The definition of MyExcelDicModel can be roughly referred to as follows:

    /**
     * 字典所属属性中文名
     */
    private String chinese;

    /**
     * 字典所属属性英文名
     */
    private String english;

    /**
     * 所有下拉值
     */
    private List<String> sourceList;

    /**
     * 在Excel 中的列名
     */
    private String excelColumnName;

    /**
     * 字典在 Excel 中的范围起始行
     */
    private Integer startExcelNum;

    /**
     * 字典在 Excel 中的范围结束行
     */
    private Integer endExcelNum;

    /**
     * 回填数据的sheet页 字典所在列索引
     */
    private Integer metaSheetColumnIndex;


insert image description here
In order to obtain the value in the formula of the specified dictionary range, startExcelNum is fixed to place the header in the first row in Excel, so it starts from the second row, and the second row in Excel is considered 2, so it is fixed to 2. Can.
insert image description here
The corresponding endExcelNum is 1 + the length of all values ​​of the dictionary sourceList .

  1. Next, we will prepare to write the header and data of the dictionary into the sheet of the dictionary. At the same time, the Excel column name specified in the above formula is the letter AZ and then AA-AZ and so on. This column name also needs us to calculate Come out and assign it to the excelColumnName in the defined MyExcelDicModel , that is, calculate the number of English characters in the table header through the column index 0 - a certain value, and use it for the assembly of the final formula
        // 表头写入   allDicList 即为我所有的字典集合
        for (int i = 0; i < allDicList.size(); i++) {
    
    
            MyExcelDicModel myExcelDicModel = allDicList.get(i);
            // 表头名称
            String chinese = myExcelDicModel.getChinese();
            // 当前列在excel 中的列名    getExcelColIndex方法见下方方法
            governanceExcelDicModel.setExcelColumnName(this.getExcelColIndex(i));
            // 获取上面已经创建好的行
            Row row = templateDicSheet.getRow(0);
            // 在当前行的指定列索引 即指定单元格内写入
            row.createCell(i).setCellValue(chinese);
        }

Calculate English column names by index

    /**
     * 将index转为excel的索引,如 A  AA  BA
     * 列名开始时从A-Z 再次出现时为AA AB - AZ 继续重复时为BA - BZ 以此类推
     * @param index 当前列的值
     * @return 当前列在Excel 中的列名
     */
    private String getExcelColIndex(int index) {
    
    
        String result = "";
        if (index / 26 != 0) {
    
    
            char x = (char) ('A' + (index / 26 - 1));
            result += x;
        }
        char l = (char) ('A' + (index % 26));
        result += l;
        return result;
    }

After the table header is completed, start to write the values ​​of all dictionaries, and at the same time assemble the formulas corresponding to the dictionaries through the name manager provided by Excel POI

        // 字典值写入单元格中
        for (int dicIndex = 0; dicIndex < allDicList.size(); dicIndex++) {
    
    
            // 当前字典
            MyExcelDicModel myExcelDicModel = allDicList.get(dicIndex);
            // 当前这一字典所有值
            List<String> sourceList = myExcelDicModel.getSourceList();
            for (int labelIndex = 0; labelIndex < sourceList.size(); labelIndex++) {
    
    
                Row row = templateDicSheet.getRow(labelIndex + 1);
                // 给到当前行当前列单元格的值
                row.createCell(dicIndex).setCellValue(sourceList.get(labelIndex));
            }

            // 给与字典多个命名空间范围  
            Name name = templateDicSheet.getWorkbook().createName();
            name.setNameName(myExcelDicModel.getEnglish());
            // excel 中公式需要的范围值
            String excelColumnName = myExcelDicModel.getExcelColumnName();
            Integer startExcelNum = myExcelDicModel.getStartExcelNum();
            Integer endExcelNum = myExcelDicModel.getEndExcelNum();
            // 字典下拉值在Excel 中的表达式 =sheet名称!$A$1:$A$10  前面英文字母标识在Excel 中的列名,后面为excel中的行号 两段加起来表示一个范围,最前方为sheet的名字 !$ 为固定写法
            name.setRefersToFormula("templateDic!$"+excelColumnName+"$"+startExcelNum+":"+"$"+excelColumnName+"$"+endExcelNum);
        }
        // 到此给Name 赋值完成即可 没有其他操作 后面即可直接引用,需要注意的是一定要在正确的sheet 对象下创建Name

(If your dictionary has only one column, then you don’t need to loop through it to write a Name)

Name name = templateDicSheet.getWorkbook().createName(); The Name
here is the name (naming) manager of excel Here, the English name of the dictionary is assigned to the named object, and the formula of the dictionary is passed through setRefersToFormula (referring to Formula) to hang the formula on this named object, and when we use this named object later, we can associate it with the formula by ourselves through the English name of the dictionary.

At this point, the Sheet of the dictionary is complete!

But we need to add another attribute to the excel we defined. When we manually operate the drop-down of Excel (see the manual operation at the top), after the sheets on both sides are created, we first select all the cell ranges that need to be given to the drop-down. Here
insert image description here
we The general range is that a certain column is required, and each row is this column. If your column is fixed, then you can directly specify the index of the fixed column. In the class MyExcelDicModel I defined, specify the value attribute of this column index The name is metaSheetColumnIndex
If your column is not fixed here, you need to calculate the index of the column from the first sheet and assign it.

  1. The method of associating the formula of the dictionary to the specified cell first uses the sheet
    to be associated to create the data validation helper object XSSFDataValidationHelper , which is similar to the following steps on the page: create the data validation helper object, and mainly fill in the data sheet
    insert image description here
XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper((XSSFSheet) sheet);

By traversing our previously customized

        for (MyExcelDicModel myExcelDicModel : dicSheetCreateList) {
    
    
            String english = myExcelDicModel.getEnglish();
            // 通过之前指定的字典英文名 关联之前定义的公式
            StringBuilder formula = new StringBuilder("=INDIRECT(\"" + english + "\"");
            formula.append(")");
            // 数据校验约束对象
            XSSFDataValidationConstraint dvConstraint =
                    new XSSFDataValidationConstraint(3, formula.toString());

            // 单元格范围指定
            Integer metaSheetColumnIndex = myExcelDicModel.getMetaSheetColumnIndex();
            // 四个入参分别为开始行,结束行,开始列,结束列 指定单元格范围 startRow,endRow 均为正整数表示开始行与结束行
            CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(startRow, endRow, metaSheetColumnIndex,
                    metaSheetColumnIndex);
            // 创建校验 将校验的单元格与约束绑定到一起创建对象
            DataValidation validation = dvHelper.createValidation(dvConstraint, cellRangeAddressList);
            // 将创建好的数据校验添加到主sheet 中即完成了校验和单元格的绑定,指定单元格此时将获得字典下拉
            sheet.addValidationData(validation);
        }

Equivalent to this process and determine the bound
insert image description here

At this point, the binding dictionary drop-down is completed.

The rest is to write the data to be written in the main sheet. It is a normal writing operation in the cell without redundant description. It is similar to writing the header, just createCell and setCellValue in the row.

Guess you like

Origin blog.csdn.net/weixin_44131922/article/details/130931746