当前位置: 首页 > 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.lqws.cn/news/513667.html

相关文章:

  • 鸿蒙ArkUI---基础组件Tabs(Tabbar)
  • ASR1606 LTE Cat.1 与 MK SD NAND–––T-BOX 智能基座的通信存储双擎
  • x86-64安装编译Apollo 9.0 aarch64版本
  • ZArchiver×亚矩云手机:云端文件管理的“超维解压”革命
  • B树和B+树的区别
  • SpringBoot项目快速开发框架JeecgBoot——数据访问!
  • 从零开始的云计算生活——第二十三天,稍作休息,Tomcat
  • pycharm基础操作备忘记录
  • 国芯思辰|同步降压转换器CN2020A替换LMR33620应用于分布式电源系统
  • Jenkins X + AI:重塑云原生时代的持续交付范式
  • Docker部署Flask应用
  • Android14音频子系统-Linux音频子系统ALSA
  • 微信小程序 / UNIAPP --- 阻止小程序返回(顶部导航栏返回、左 / 右滑手势、安卓物理返回键和调用 navigateBack 接口)
  • 服务器性能优化通用方案
  • 文档处理控件Aspose.Words教程:在.NET中将多页文档转换为单个图像
  • 【开源解析】基于PyQt5的智能费用报销管理系统开发全解:附完整源码
  • Golang单例实现
  • LVS-NAT负载均衡群集实战:原理、部署与问题排查
  • 小程序快速获取url link方法,短信里面快速打开链接
  • Spark Streaming 与 Flink 实时数据处理方案对比与选型指南
  • Flink2.0 配置 historyserver
  • 15个AI模拟面试平台 和 简历修改 / 真人面试平台
  • 云计算产业链
  • 用wordpress建日语外贸网站的优势
  • C# Avalonia 绑定模式 Mode 的区别,它们的应用场景
  • spring中的@Cacheable缓存
  • MicroPython网络编程:AP模式与STA模式详解
  • 【笔记——李沐动手学深度学习】2.3 线性代数
  • 【Python练习】012. 使用字符串的upper()方法将字符串转换为大写
  • 基于开源AI大模型、AI智能名片与S2B2C商城小程序的美食菜单社交化营销创新研究