sirwsl的博客

EasyExcel下拉列表无法显示

故事

最近在一个项目上涉及到数据的导入导出,由于数据在导入时,需要指定一下excel模板,而模板中为了解析方便设置了下拉框限制。本来项目跑的好好的,谁知道,这两天下载的模板文件下拉框不会显示了,绝绝子,最终问题解决了。

解决方式

原来有方式是采用createExplicitListConstraint 进行设置枚举下拉,但是存在很大弊端,数据过多会导致无法显示。
后来通过将下拉数据存于隐藏的sheet中,通过excel中的公式进行设置,这样问题就得到解决。

关键代码

设置TitleHandler继承CellWriteHandler,之后在afterCellDispose进行数据的样式、下拉等操作设置,具体如下:

// 原有的设置下拉的方式
//                String[] datas = dropDownMap.get(cell.getColumnIndex());
//                DataValidationHelper dvHelper = sheet.getDataValidationHelper();
//                DataValidationConstraint dvConstraint = dvHelper
//                        .createExplicitListConstraint(datas);
//                CellRangeAddressList addressList = null;
//                DataValidation validation = null;
//                for (int i = 1; i < 1000; i++) {
//                    addressList = new CellRangeAddressList(i, i, cell.getColumnIndex(), cell.getColumnIndex());
//                    validation = dvHelper.createValidation(
//                            dvConstraint, addressList);
//                    sheet.addValidationData(validation);
//                }
                //设置下拉框
                DataValidationHelper helper = sheet.getDataValidationHelper();
                //定义sheet的名称

                String hiddenName = "hidden";
                Sheet hidden=workbook.getSheet(hiddenName);
                for (Map.Entry<Integer, String[]> entry : dropDownMap.entrySet()) {
                    //下拉框的起始行,结束行,起始列,结束列
                    CellRangeAddressList addressList = new CellRangeAddressList(1, 65000, entry.getKey(), entry.getKey());
                    //获取excel列名
                    String excelLine = getExcelLine(entry.getKey());

                    //2.循环赋值
                    String[] values = entry.getValue();
                    //2.循环赋值
                    for (int i = 0, length = values.length; i < length; i++) {
                        // 3:表示你开始的行数  3表示 你开始的列数
                        Row row = hidden.getRow(i);
                        if (row == null) {
                            row = hidden.createRow(i);
                        }
                        row.createCell(entry.getKey()).setCellValue(values[i]);
                    }
                    //4.  =hidden!$H:$1:$H$50  sheet为hidden的 H1列开始H50行数据获取下拉数组
                    String refers = "=" + hiddenName + "!$" + excelLine +
                            "$1:$" + excelLine + "$" + (values.length+1);
                    //5 将刚才设置的sheet引用到你的下拉列表中
                    DataValidationConstraint constraint = helper.createFormulaListConstraint(refers);
                    DataValidation dataValidation = helper.createValidation(constraint, addressList);
                    writeSheetHolder.getSheet().addValidationData(dataValidation);
                }
                //设置列为隐藏
                int hiddenIndex = workbook.getSheetIndex(hiddenName);
                if (!workbook.isSheetHidden(hiddenIndex)) {
                    workbook.setSheetHidden(hiddenIndex, true);
                }
            }

完整代码

import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.util.StyleUtil;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <pre>
 *  操作标题行单元格颜色
 * @author sirwsl
 */
@Slf4j
public class TitleHandler implements CellWriteHandler {

    /**
     * 操作列
     */
    private final List<Integer> columnIndex;
    /**
     * 颜色
     */
    private final Short colorIndex;
    /**
     * 批注<列的下标,批注内容>
      */
    private Map<Integer,String> annotationsMap;
    /**
     * 下拉框值
     */
    private Map<Integer, String[]> dropDownMap;

    public TitleHandler(List<Integer> columnIndex, Short colorIndex, Map<Integer, String> annotationsMap) {
        this.columnIndex = columnIndex;
        this.colorIndex = colorIndex;
        this.annotationsMap = annotationsMap;
    }

    public TitleHandler(List<Integer> columnIndex, Short colorIndex) {
        this.columnIndex = columnIndex;
        this.colorIndex = colorIndex;
    }

    public TitleHandler(List<Integer> columnIndex, Short colorIndex, Map<Integer, String> annotationsMap, Map<Integer, String[]> dropDownMap) {
        this.columnIndex = columnIndex;
        this.colorIndex = colorIndex;
        this.annotationsMap = annotationsMap;
        this.dropDownMap = dropDownMap;
    }

    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        if (isHead) {
            // 设置列宽
            Sheet sheet = writeSheetHolder.getSheet();
            //sheet.setColumnWidth(cell.getColumnIndex(), 14 * 256);
            writeSheetHolder.getSheet().getRow(0).setHeight((short) (1.8 * 256));
            Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
            Drawing<?> drawing = sheet.createDrawingPatriarch();

            // 设置标题字体样式
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            WriteFont headWriteFont = new WriteFont();
            headWriteFont.setFontName("宋体");
            headWriteFont.setFontHeightInPoints((short)14);
            headWriteFont.setBold(true);
            if (CollectionUtils.isNotEmpty(columnIndex) &&
                    colorIndex != null &&
                    columnIndex.contains(cell.getColumnIndex())) {
                // 设置字体颜色
                headWriteFont.setColor(colorIndex);
            }
            headWriteCellStyle.setWriteFont(headWriteFont);
            headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
            CellStyle cellStyle = StyleUtil.buildHeadCellStyle(workbook, headWriteCellStyle);
            cell.setCellStyle(cellStyle);

            if (null != annotationsMap && annotationsMap.containsKey(cell.getColumnIndex())) {
                // 批注内容
                String context = annotationsMap.get(cell.getColumnIndex());
                // 创建绘图对象
                Comment comment = drawing.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), 0, (short) cell.getColumnIndex() + 3, 1));
                comment.setString(new XSSFRichTextString(context));
                cell.setCellComment(comment);
            }

            if (null != dropDownMap &&
                    !dropDownMap.isEmpty() &&
                    dropDownMap.containsKey(cell.getColumnIndex())) {
//                String[] datas = dropDownMap.get(cell.getColumnIndex());
//                DataValidationHelper dvHelper = sheet.getDataValidationHelper();
//                DataValidationConstraint dvConstraint = dvHelper
//                        .createExplicitListConstraint(datas);
//                CellRangeAddressList addressList = null;
//                DataValidation validation = null;
//                for (int i = 1; i < 1000; i++) {
//                    addressList = new CellRangeAddressList(i, i, cell.getColumnIndex(), cell.getColumnIndex());
//                    validation = dvHelper.createValidation(
//                            dvConstraint, addressList);
//                    sheet.addValidationData(validation);
//                }
                //设置下拉框
                DataValidationHelper helper = sheet.getDataValidationHelper();
                //定义sheet的名称

                String hiddenName = "hidden";
                Sheet hidden=workbook.getSheet(hiddenName);
                for (Map.Entry<Integer, String[]> entry : dropDownMap.entrySet()) {
                    //下拉框的起始行,结束行,起始列,结束列
                    CellRangeAddressList addressList = new CellRangeAddressList(1, 65000, entry.getKey(), entry.getKey());
                    //获取excel列名
                    String excelLine = getExcelLine(entry.getKey());

                    //2.循环赋值
                    String[] values = entry.getValue();
                    //2.循环赋值
                    for (int i = 0, length = values.length; i < length; i++) {
                        // 3:表示你开始的行数  3表示 你开始的列数
                        Row row = hidden.getRow(i);
                        if (row == null) {
                            row = hidden.createRow(i);
                        }
                        row.createCell(entry.getKey()).setCellValue(values[i]);
                    }
                    //4.  =hidden!$H:$1:$H$50  sheet为hidden的 H1列开始H50行数据获取下拉数组
                    String refers = "=" + hiddenName + "!$" + excelLine +
                            "$1:$" + excelLine + "$" + (values.length+1);
                    //5 将刚才设置的sheet引用到你的下拉列表中
                    DataValidationConstraint constraint = helper.createFormulaListConstraint(refers);
                    DataValidation dataValidation = helper.createValidation(constraint, addressList);
                    writeSheetHolder.getSheet().addValidationData(dataValidation);
                }
                //设置列为隐藏
                int hiddenIndex = workbook.getSheetIndex(hiddenName);
                if (!workbook.isSheetHidden(hiddenIndex)) {
                    workbook.setSheetHidden(hiddenIndex, true);
                }
            }
        }
    }
        /**
         *  返回excel列标A-Z-AA-ZZ
         * @param num 列数
         * @return java.lang.String
         */
        public static String getExcelLine ( int num){
            String line = "";
            int first = num / 26;
            int second = num % 26;
            if (first > 0) {
                line = (char) ('A' + first - 1) + "";
            }
            line += (char) ('A' + second) + "";
            return line;
        }

}

调用方式:


//设置下拉
HashMap<Integer, String[]> drop = new HashMap<>(16);
drop.put(0, Arrays.asList("A","B","C"));
drop.put(1, Arrays.asList("A","B","C"));
//设置提示
HashMap<Integer, String> annotations = new HashMap<>();
annotations.put(0, "提示1");
annotations.put(1, "提示2");
//设置颜色
List<Integer> columns = Arrays.asList(0, 1, 2, 3, 4); 
TitleHandler handler= new TitleHandler(columns, IndexedColors.RED.index, annotations, drop);
//创建
 ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
// 表头样式
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
 // 单元格样式
 WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
 // 初始化表格样式
HorizontalCellStyleStrategy horizontal = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
WriteSheet hidden = EasyExcel.writerSheet(0, "hidden").build();
WriteSheet sheet1 = EasyExcel.writerSheet(1, "测试")
                .head(BO.class)
                .registerWriteHandler(horizontal )
                .registerWriteHandler(handler)
                .build();
excelWriter.write(dataList,hidden)
                .write(dataList, sheet1);
 excelWriter.finish();

标题:EasyExcel下拉列表无法显示
作者:sirwsl
地址:https://www.wslhome.top/articles/2022/02/24/1645664626098.html