当前位置: 首页 > news >正文

springboot+easyexcel实现下载excels模板下拉选择

定义下拉注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelDropDown {
    /**
     * 固定下拉选项
     */
    String[] source() default {};

    /**
     * 动态数据源key(从上下文中获取)
     */
    String sourceMethod() default "";

    /**
     * 下拉框起始行(默认从第2行开始)
     */
    int firstRow() default 1;

    /**
     * 下拉框结束行(默认到10000行)
     */
    int lastRow() default 10000;
}

实现CellWriteHandler 接口


@Slf4j
public class DynamicDropDownHandler implements CellWriteHandler {
    private final ApplicationContext applicationContext;

    public DynamicDropDownHandler(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @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) {


        Class clazz = writeSheetHolder.getClazz();
        try {
            String fieldName = head.getFieldName();
            Field field = clazz.getDeclaredField(fieldName);
            ExcelDropDown dropDown = field.getAnnotation(ExcelDropDown.class);
            if (dropDown != null) {
                String[] source = dropDown.source();

                if (source.length == 0) {
                    //判断是否有从库中查询数据的方法
                    String method = dropDown.sourceMethod();
                    if (null != method && !"".equals(method)) {
                        source = applicationContext.getBean(method, String[].class);
                    }
                    if (source.length == 0) {
                        return;
                    }

                }

                Sheet sheet = writeSheetHolder.getSheet();
                Workbook workbook = sheet.getWorkbook();
                // 1. 创建隐藏Sheet存储下拉选项
                String optionSheetName = fieldName+"_options";
                Sheet optionsSheet = workbook.getSheet(optionSheetName);
                if (optionsSheet == null) {
                    optionsSheet = workbook.createSheet(optionSheetName);
                    workbook.setSheetHidden(workbook.getSheetIndex(optionsSheet), true); // 隐藏Sheet
                }
                // 2. 写入选项数据到隐藏Sheet
                int optionCol = 0; // 使用第一列存储选项
                for (int i = 0; i < source.length; i++) {
                    Row row = optionsSheet.getRow(i);
                    if (row == null) {
                        row = optionsSheet.createRow(i);
                    }
                    row.createCell(optionCol).setCellValue(source[i]);
                }

                // 3. 创建名称引用
                String rangeName = "DROP_DOWN_" + fieldName.toUpperCase();
                Name namedRange = workbook.getName(rangeName);
                if (namedRange == null) {
                    namedRange = workbook.createName();
                    namedRange.setNameName(rangeName);
                }
                namedRange.setRefersToFormula(
                        String.format(optionSheetName+"!$A$1:$A$%d", source.length)
                );
                // 4. 设置数据验证(使用公式引用)
                DataValidationHelper helper = sheet.getDataValidationHelper();
                DataValidationConstraint constraint =
                        helper.createFormulaListConstraint(rangeName);

                // 设置下拉范围:从第二行开始到最大行,当前列
                int columnIndex = cell.getColumnIndex();
                CellRangeAddressList addressList = new CellRangeAddressList(
                        1, // 从第二行开始
                        2, // Excel最大行号
                        columnIndex,
                        columnIndex
                );
                DataValidation validation = helper.createValidation(constraint, addressList);
                validation.setSuppressDropDownArrow(true);
                validation.setShowErrorBox(true);
                sheet.addValidationData(validation);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

    }
}

使用下载模板接口

    public void downloadTemplate(HttpServletResponse response) {
        try {
            // 设置响应头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("模板", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            // 写入Excel
            EasyExcel.write(response.getOutputStream(), ImportVo.class)
                    .autoCloseStream(true)
                    .registerWriteHandler(new DynamicDropDownHandler(applicationContext))
                    .sheet("Sheet")
                    .doWrite(Collections.singletonList(Collections.emptyList())); 
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

实体类

public class ImportVo {
	@ExcelProperty(value = "动态数据下拉")
    @ExcelDropDown(sourceMethod = "getNameList")
    private String name;
    @ExcelProperty(value = "性别")
    @ExcelDropDown(source = {"男","女"})
    private String sex;
}
http://www.dtcms.com/a/108876.html

相关文章:

  • Spring Boot 的配置文件
  • 网络空间安全(50)JavaScript基础语法
  • C#:重构(refactoring)
  • 【Spring Cloud Alibaba】:Nacos 使用全详解
  • CExercise04_1位运算符_1 用位运算符判断某个整数是否为奇数
  • 购物车(V2装饰器)
  • 算法:优选(1)
  • RK3568驱动 SPI主/从 配置
  • 基于微信小程序的医院挂号预约系统设计与实现
  • Apache Doris 2025 Roadmap:构建 GenAI 时代实时高效统一的数据底座
  • WRF-Chem 中出现real.exe错误(psfc 计算问题)- MOZART
  • Apache BookKeeper Ledger 的底层存储机制解析
  • 配置单区域OSPF
  • ARM—LED,看门狗关闭,按钮,时钟,PWM定时器,蜂鸣器
  • 【前端扫盲】postman介绍及使用
  • 走向多模态AI之路(三):多模态 AI 的挑战与未来
  • 【家政平台开发(12)】家政平台数据库设计:从MySQL到MyBatis-Plus实战
  • 多个参考文献插入、如何同时插入多个参考文献:如[1,2]、[1-3]格式
  • 搬砖--贪心+排序的背包
  • 请谈谈分治算法,如何应用分治算法解决大规模问题?
  • Pico4 Pro VR 和HTC Vivi 哪个好些
  • ngx_getpid() ngx_parent = ngx_getppid()
  • [C语言笔记]09、指针
  • 代码随想录Day31
  • 作用域与上下文:JavaScript魔法森林探秘
  • Python每日一题(14)
  • J1 ResNet-50算法实战与解析
  • JavaScript学习18-css操作和事件处理程序(html/DOM0/DOM2)
  • 蓝桥杯Java B组省赛真题高频考点近6年统计分类
  • 职坐标解析AI风口职业发展新机遇