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

通用 Excel 导出功能设计与实现:动态列选择与灵活配置

在企业级应用开发中,数据导出是高频需求。本文介绍一种支持动态列选择、灵活配置的通用 Excel 导出方案,通过前后端协同设计,实现导出字段、列顺序、数据格式的自定义,满足多样化业务场景。

一、功能架构设计

核心特性

  1. 动态字段选择:支持通过前端勾选动态指定导出字段,包含字段名(逻辑标识)与显示名(业务含义)的映射
  1. 行数据过滤:支持按用户 ID 筛选导出特定行数据
  1. 多 Sheet 支持:可扩展支持单个 Excel 文件包含多个 Sheet 页
  1. 格式自适应:自动处理日期、数字等数据类型的格式化显示

技术栈

  • 前端:Thymeleaf 模板引擎 + XMLHttpRequest 文件下载
  • 后端:Spring Boot + EasyExcel + Hutool 工具集
  • 核心组件
  • 请求参数:ExcelExportRequest(包含基础配置与字段列表)
  • 响应结构:ExcelExportResponse(封装文件元信息与 Sheet 数据)

二、核心实现细节

1. 前后端数据协议设计

入参结构(ExcelExportRequest)
@Datapublic class UserExportRequest extends ExcelExportRequest {private List<Integer> userIdList; // 待导出的用户ID列表(可选)}@Datapublic class ExcelExportRequest {private String excelName; // Excel文件名private String sheetName; // Sheet页名称private List<ExcelExportField> fieldList; // 导出字段列表(有序)}@Datapublic class ExcelExportField {private String fieldName; // 实体类字段名(如"userId")private String fieldDesc; // 表格显示名称(如"用户ID")}
出参结构(ExcelExportResponse)
@Datapublic class ExcelExportResponse {private String excelName; // 导出文件名private List<ExcelSheet> sheetList; // Sheet数据集合@Datapublic static class ExcelSheet {private String sheetName; // Sheet名称private List<ExcelHead> headList; // 表头信息private List<Map<String, String>> dataList; // 行数据(键值对形式)@Datapublic static class ExcelHead {private String fieldName; // 字段名private String fieldDesc; // 显示名}}}

2. 前端交互实现

动态列选择组件

<!-- 案例1:仅列选择 --><table border="1"><caption><span class="title">案例1:勾选需要导出的列</span><button onclick="exportExcel1(event)">导出</button></caption><tr><th><label><input type="checkbox" class="exportCol" data-field-name="userId" data-field-desc="用户id"> 用户id</label></th><th><label><input type="checkbox" class="exportCol" data-field-name="userName" data-field-desc="用户名">用户名</label></th><!-- 更多字段... --></tr></table><!-- 案例2:列选择+行筛选 --><table border="1"><caption><span class="title">案例2:勾选需要导出的列 & 行</span><button onclick="exportExcel2(event)">导出</button></caption><tr><th>选择记录</th><th><label><input type="checkbox" class="exportCol" data-field-name="userId" data-field-desc="用户id"> 用户id</label></th><!-- 更多字段... --></tr><tr th:each="user:${userList}"><td><input type="checkbox" class="userId" th:data-user-id="${user.userId}"></td><td th:text="${user.userId}"></td><!-- 数据行展示... --></tr></table>
文件下载逻辑
function download(data, url) {const xhr = new XMLHttpRequest();xhr.open("POST", url);xhr.responseType = 'blob';xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8');xhr.onload = function() {if (this.status === 200) {const blob = this.response;if (blob.size > 0) {// 从响应头解析文件名const fileName = getFileNameFromResponse(this.getResponseHeader("content-disposition"));// 创建临时链接下载const a = document.createElement('a');a.href = URL.createObjectURL(blob);a.download = fileName;a.click();}}};xhr.send(JSON.stringify(data));}// 文件名解析工具function getFileNameFromResponse(disposition) {const match = /filename=(.*)/.exec(disposition);return decodeURIComponent(match[1].replace(/['"]/g, ''));}

3. 后端核心处理

控制器设计
@Controller@CrossOriginpublic class UserController {@Resource private UserService userService;// 页面跳转@GetMapping("/userList")public String userList(Model model) {model.addAttribute("userList", userService.getUserList());return "userList";}// 导出接口@PostMapping("/userExport")public void userExport(@RequestBody UserExportRequest request) throws IOException {ExcelExportResponse response = userService.userExport(request);ExcelExportUtils.writeExcelToResponse(response);}}
业务层逻辑
@Servicepublic class UserServiceImpl implements UserService {@Overridepublic ExcelExportResponse userExport(UserExportRequest request) {List<User> dataList;// 处理行筛选逻辑if (CollectionUtil.isEmpty(request.getUserIdList())) {dataList = getUserList(); // 导出全部数据} else {dataList = getUserList(request.getUserIdList()); // 按ID筛选}// 构建导出数据return ExcelExportUtils.build(dataList, request);}// 模拟数据获取private List<User> getUserList() {List<User> list = new ArrayList<>();for (int i = 1; i <= 10; i++) {list.add(new User(i, "用户名-" + i, 20 + i, "地址-" + i));}return list;}}
导出工具类
public class ExcelExportUtils {public static ExcelExportResponse build(List<?> dataList, ExcelExportRequest request) {ExcelExportResponse result = new ExcelExportResponse();result.setExcelName(request.getExcelName());List<ExcelSheet> sheetList = new ArrayList<>();ExcelSheet sheet = new ExcelSheet();sheet.setSheetName(request.getSheetName());// 构建表头(保持字段顺序)sheet.setHeadList(buildSheetHeadList(request.getFieldList()));// 构建数据行(通过反射获取字段值)sheet.setDataList(buildSheetDataList(dataList, request.getFieldList()));sheetList.add(sheet);result.setSheetList(sheetList);return result;}private static List<ExcelSheet.ExcelHead> buildSheetHeadList(List<ExcelExportField> fields) {return fields.stream().map(field -> new ExcelSheet.ExcelHead(field.getFieldName(), field.getFieldDesc())).collect(Collectors.toList());}// 反射获取对象字段值private static List<Map<String, String>> buildSheetDataList(List<?> dataList, List<ExcelExportField> fields) {return dataList.stream().map(obj -> {Map<String, String> row = new HashMap<>();fields.forEach(field -> {Object value = ReflectUtil.getFieldValue(obj, field.getFieldName());row.put(field.getFieldName(), Objects.toString(value, ""));});return row;}).collect(Collectors.toList());}// 响应输出处理public static void writeExcelToResponse(ExcelExportResponse result) throws IOException {HttpServletResponse response = getResponse();response.setContentType("application/vnd.ms-excel");response.setHeader("Content-Disposition","attachment; filename=" + URLEncodeUtil.encode(result.getExcelName() + ".xlsx"));try (ExcelWriter writer = EasyExcel.write(response.getOutputStream()).build()) {result.getSheetList().forEach(sheet -> {WriteSheet writeSheet = EasyExcel.writerSheet(sheet.getSheetName()).build();// 写入表头与数据writer.write(buildEasyExcelData(sheet), writeSheet);});}}}

三、方案优势分析

  1. 灵活性:通过fieldList实现导出字段的动态排序与筛选,适应不同业务视图需求
  1. 扩展性:支持添加多 Sheet、数据格式化(如日期转换)、样式配置等扩展功能
  1. 易用性:前端可视化勾选操作,后端自动处理反射映射,降低使用门槛
  1. 性能优化:通过工具类封装重复逻辑,减少代码冗余,提升开发效率

四、应用场景

  • 数据报表导出:支持不同角色用户自定义报表字段
  • 批量数据下载:结合行筛选功能实现精准数据提取
  • 系统对接:为第三方系统提供标准化 Excel 数据输出接口

通过该方案,开发者可快速实现具备灵活配置能力的 Excel 导出功能,同时保持代码的可维护性与扩展性。实际应用中可根据业务需求,进一步扩展数据格式化、单元格样式、多语言支持等高级功能。

http://www.lryc.cn/news/575176.html

相关文章:

  • 国道观察者手记
  • React + Umi(Umijs/Max) 搭建项目及配置
  • 大学专业科普 | 物联网、自动化和人工智能
  • 多服务器IP白名单配置(使用redis stream实现)
  • 神经网络的运作方式类比讲解
  • 【EI会议征稿】东北大学主办第三届机器视觉、图像处理与影像技术国际会议(MVIPIT 2025)
  • Arm架构下麒麟V10桌面版安装MySQL
  • Android14音频子系统-Linux音频子系统ASoC-ALSA
  • Linux size命令详解
  • Android14音频子系统-Linux音频子系统ALSA
  • MFC对话框启动时就隐藏窗口
  • 开疆智能CCLinkIE转ModbusTCP网关连接脉冲计数器配置案例
  • matlab机器人工具箱(Robotics Toolbox)安装及使用
  • 分布式系统 - 分布式缓存及方案实现
  • python网络自动化-数据格式与数据建模语言
  • 如何快速将iPhone中的文本保存到电脑上
  • 基于SSM框架+mysql实现的监考安排管理系统[含源码+数据库+项目开发技术手册]
  • PHP爬虫实战:轻松获取京东商品SKU信息
  • 计算机网络-----详解HTTP协议
  • 【编程基本功】Win11中Git安装配置全攻略,包含Git以及图形化工具TortoiseGit
  • 芯谷科技--升压/升降压DC-DC转换器D5209
  • 无人船:科技驱动,快速发展,前景广阔
  • 云计算产业链
  • pscc系统如何部署,怎么更安全更便捷?
  • 【EDA软件】【应用功能子模块网表提供和加载编译方法】
  • 【番外篇】TLS指纹
  • sentinel与seata组件在微服务中的基本作用
  • 文档处理控件Aspose.Words教程:在.NET中将多页文档转换为单个图像
  • AES加密:为你的PDF文档加上一道钢铁防线
  • 用Rust写平衡三进制乘法器