EasyExel解决下拉选超过50个的问题

本文涉及的产品
可视分析地图(DataV-Atlas),3 个项目,100M 存储空间
数据可视化DataV,5个大屏 1个月
简介: easyexcel下拉选

避免下拉选过多导致不显示的问题,将下拉选的内容存在另一个sheet页中。

1、Controller

    @GetMapping("/download")
    @ApiOperation(value = "下载导入模板")
    public void download(@RequestParam(required = true) Integer projectId, HttpServletResponse response) throws IOException {
        //导出模板名称
        String fileName = "导入模板";
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        //这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileNameEncode = URLEncoder.encode(fileName, "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileNameEncode + ExcelTypeEnum.XLS.getValue());
        //设置下拉框内容
        Map<Integer, List<String>> selectMap = new HashMap<>();
        //模拟下拉选内容
        List<String> list1 = new ArrayList<>();
        list1.add("硬件传输");
        list1.add("人工录入");
        List<String> list2 = new ArrayList<>();
        list2.add("r/min");
        ...
        list2.add("m³");
        selectMap.put(1, list1);
        selectMap.put(2, list2);
        //表头
        List<EnergyType> list = new ArrayList<>();
        EasyExcelFactory.write(response.getOutputStream())
                .registerWriteHandler(new SelectDataSheetWriteHandler(selectMap))//设置字典
                .registerWriteHandler(new SimpleColumnWidthStyleStrategy(17))//设置列宽度
                .registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 28, (short) 18))//设置行高度
                .head(EnergyType.class)//此处对应的是实体类
                .excelType(ExcelTypeEnum.XLS)//设置导出格式为xls后缀
                .sheet("sheet1")
                .doWrite(list);
    }

2、处理字典项的handler

package com.energy.util;

import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.hssf.usermodel.HSSFDataValidation;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;

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

/**
 * @author: CUI
 * @date: 2022-05-27 9:11
 */
public class SelectDataSheetWriteHandler implements SheetWriteHandler {
    private Map<Integer, List<String>> selectMap;

    private char[] alphabet = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
            'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};

    public SelectDataSheetWriteHandler(Map<Integer, List<String>> selectMap) {
        this.selectMap = selectMap;
    }

    @Override
    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        if (selectMap == null || selectMap.size() == 0) {
            return;
        }

        // 需要设置下拉框的sheet页
        Sheet curSheet = writeSheetHolder.getSheet();
        DataValidationHelper helper = curSheet.getDataValidationHelper();
        String dictSheetName = "sheet2";
        Workbook workbook = writeWorkbookHolder.getWorkbook();
        // 数据字典的sheet页
        Sheet dictSheet = workbook.createSheet(dictSheetName);
        // 隐藏数据字典的sheet页
        workbook.setSheetHidden(workbook.getSheetIndex(dictSheet), true);
        for (Map.Entry<Integer, List<String>> entry : selectMap.entrySet()) {
            // 设置下拉单元格的首行、末行、首列、末列
            CellRangeAddressList rangeAddressList = new CellRangeAddressList(1, 65533, entry.getKey(), entry.getKey());
            int rowLen = entry.getValue().size();
            // 设置字典sheet页的值 每一列一个字典项
            for (int i = 0; i < rowLen; i++) {
                Row row = dictSheet.getRow(i);
                if (row == null) {
                    row = dictSheet.createRow(i);
                }
                row.createCell(entry.getKey()).setCellValue(entry.getValue().get(i));
            }
            String excelColumn = getExcelColumn(entry.getKey());
            // 下拉框数据来源 eg:字典sheet!$B1:$B2
            String refers = dictSheetName + "!$" + excelColumn + "$1:$" + excelColumn + "$" + rowLen;
            // 创建可被其他单元格引用的名称
            Name name = workbook.createName();
            // 设置名称的名字
            name.setNameName("dict" + entry.getKey());
            // 设置公式
            name.setRefersToFormula(refers);
            // 设置引用约束
            DataValidationConstraint constraint = helper.createFormulaListConstraint("dict" + entry.getKey());
            // 设置约束
            DataValidation validation = helper.createValidation(constraint, rangeAddressList);
            if (validation instanceof HSSFDataValidation) {
                validation.setSuppressDropDownArrow(false);
            } else {
                validation.setSuppressDropDownArrow(true);
                validation.setShowErrorBox(true);
            }
            // 阻止输入非下拉框的值
            validation.setErrorStyle(DataValidation.ErrorStyle.STOP);
            validation.createErrorBox("提示", "此值与单元格定义格式不一致!");
            // 添加下拉框约束
            writeSheetHolder.getSheet().addValidationData(validation);
        }
    }

    /**
     * 将数字列转化成为字母列
     * @param num
     * @author: CUI
     * @date: 2022-05-27 9:12
     * @return: java.lang.String
     */
    private String getExcelColumn(int num) {
        String column = "";
        int len = alphabet.length - 1;
        int first = num / len;
        int second = num % len;
        if (num <= len) {
            column = alphabet[num] + "";
        } else {
            column = alphabet[first - 1] + "";
            if (second == 0) {
                column = column + alphabet[len] + "";
            } else {
                column = column + alphabet[second - 1] + "";
            }
        }
        return column;
    }
}

为了用户体验,将字段sheet隐藏,使用workbook.setSheetHidden设置true即可。

3、实体类

package com.energy.model.entity;


import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotBlank;
import java.util.Date;

/**
 * (EnergyType)表实体类
 *
 * @author CUI
 * @since 2022-05-25 20:31:09
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("energy_type")
public class EnergyType extends Model<EnergyType> {
    //唯一标识
    @ExcelIgnore
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    //类型名称
    @ApiModelProperty(value = "类型名称")
    @ExcelProperty(value = "类型名称" , index = 0)
    @NotBlank(message = "类型名称不能为空")
    private String name;
    //数据来源
    @ApiModelProperty(value = "数据来源")
    @ExcelProperty(value = "数据来源" , index = 1)
    @NotBlank(message = "数据来源不能为空")
    private String source;
    //计量单位
    @ApiModelProperty(value = "计量单位")
    @ExcelProperty(value = "计量单位" , index = 2)
    @NotBlank(message = "计量单位不能为空")
    private String measure;
    //计费方式
    @ExcelIgnore
    @ApiModelProperty(value = "计费方式")
    private String billType;
    //描述
    @ExcelProperty(value = "描述" , index = 3)
    @ApiModelProperty(value = "描述")
    private String description;
    //创建人ID
    @ExcelIgnore
    @ApiModelProperty(value = "创建人ID")
    private Integer inUserSysNo;
    //修改人ID
    @ExcelIgnore
    @ApiModelProperty(value = "修改人ID")
    private Integer editUserSysNo;
    //是否生效
    @ExcelIgnore
    @ApiModelProperty(value = "是否生效")
    private Integer commonStatus;
    //创建人用户名
    @ExcelIgnore
    @ApiModelProperty(value = "创建人用户名")
    private String creator;
    //创建时间
    @ExcelIgnore
    @ApiModelProperty(value = "创建时间")
    private Date createTime;
    //修改时间
    @ExcelIgnore
    @ApiModelProperty(value = "修改时间")
    private Date updateTime;
    //所属项目ID
    @ExcelIgnore
    @ApiModelProperty(value = "所属项目ID")
    private Integer projectId;
}

导出的文件示例

image.png

image.png

4、注解

具体的注解含义可参照官方文档


相关实践学习
DataV Board用户界面概览
本实验带领用户熟悉DataV Board这款可视化产品的用户界面
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
目录
相关文章
点击增加按钮,添加input,超过三个则增加按钮隐藏
点击增加按钮,添加input,超过三个则增加按钮隐藏
90 0
当电量少于百分之20的时候,字体显示红色
当电量少于百分之20的时候,字体显示红色
33 0
日历控件input框默认显示当日日期
日历控件input框默认显示当日日期
78 0
|
前端开发 C# 容器
自定义面板优化统计标题卡
自定义面板优化统计标题卡
45 0
|
移动开发 JavaScript HTML5
输入售价后点击计算税费,自动显示在税费输入框!
输入售价后点击计算税费,自动显示在税费输入框!
95 0
输入售价后点击计算税费,自动显示在税费输入框!
|
前端开发 JavaScript NoSQL
[前端]每间隔一段时间查询接口获取到百分比,在页面上按照百分比展示进度条,百分比进度后下载文件
[前端]每间隔一段时间查询接口获取到百分比,在页面上按照百分比展示进度条,百分比进度后下载文件
|
小程序
小程序使用样式控制显示的行数,超出使用...显示
小程序使用样式控制显示的行数,超出使用...显示
171 0
|
前端开发 JavaScript 容器
第三方工具 - echarts中 设置x||y轴文案、提示文字等为固定字数,超出显示"..."
起初看到这种需求的时候,我是这个状态 对,我是拒绝的,人家echats画出来就是一个canvas,你让我怎么加... 但是,作为一个“有点追求的”前端,我得想招试试总结下来,唯一的突破点就是echarts的配置了。
1709 0