Skip to content

Excel 导出技术文档

1. 模块概述

Excel 导出模块是系统核心功能之一,基于 fastexcel 库实现,提供了简单、高效的 Excel 导出功能。该模块支持自定义文件名、自动调整列宽、Long 类型转换等特性,适用于各种业务场景下的 Excel 数据导出需求。

2. 核心功能

  • 简单易用: 提供单方法调用,简化 Excel 导出流程
  • 自定义文件名: 支持动态指定导出文件名
  • 自动列宽: 自动根据内容调整列宽,提升可读性
  • Long 类型转换: 自动将 Long 类型转换为字符串,避免科学计数法问题
  • 异常处理: 完善的异常处理机制,确保系统稳定性
  • 响应重置: 导出失败时自动重置响应,返回标准错误信息

3. 代码解析

3.1 类定义

java
public class ExcelUtils {
    // 类实现
}
  • 工具类设计,无需实例化即可使用
  • 提供静态方法,便于直接调用

3.2 核心方法

java
public static void exportExcel(@NotNull HttpServletResponse response, @NotNull String fileName, Class<?> clazz, Collection<?> list) throws IOException {
    // 方法实现
}

参数说明

参数名类型描述
responseHttpServletResponseHTTP响应对象,用于输出Excel文件
fileNameString导出文件名,不含扩展名
clazzClass<?>数据类型类,用于定义Excel表头
listCollection<?>导出数据集合

方法流程

  1. 设置响应头信息,包括内容类型、字符编码和文件名
  2. 获取输出流
  3. 使用 EasyExcel 写入数据
  4. 注册写入处理器,自动调整列宽
  5. 注册类型转换器,处理 Long 类型转换
  6. 执行写入操作
  7. 异常处理,重置响应并返回错误信息

3.3 核心实现细节

3.3.1 响应头设置

java
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8) + ".xlsx");
  • application/vnd.ms-excel: 表示Excel文件类型
  • utf-8: 确保文件名正确显示中文
  • Content-Disposition: 指示浏览器以附件形式下载文件

3.3.2 EasyExcel 配置

java
EasyExcel.write(outputStream, clazz)
        .autoCloseStream(true)
        .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
        .registerConverter(new LongStringConverter())
        .sheet("")
        .doWrite(list);
  • autoCloseStream(true): 自动关闭输出流
  • LongestMatchColumnWidthStyleStrategy: 自动调整列宽
  • LongStringConverter: 处理Long类型转换为字符串
  • sheet(""): 创建默认工作表
  • doWrite(list): 执行写入操作

3.3.3 异常处理

java
try {
    // 导出逻辑
} catch (Exception e) {
    // 重置response
    response.reset();
    response.setContentType("application/json");
    response.setCharacterEncoding("utf-8");
    Result<?> result = new Result<>().error("下载文件失败" + e.getMessage());
    response.getWriter().println(JSONUtil.toJsonStr(result));
}
  • 捕获所有异常,确保系统稳定性
  • 重置响应,返回JSON格式错误信息
  • 错误信息包含具体异常描述

4. 使用示例

4.1 定义数据模型

java
@Data
public class UserExcel {
    @ExcelProperty("用户ID")
    private Long userId;
    
    @ExcelProperty("用户名")
    private String username;
    
    @ExcelProperty("邮箱")
    private String email;
    
    @ExcelProperty("创建时间")
    private Date createTime;
}
  • 使用 @ExcelProperty 注解定义表头名称
  • 支持基本数据类型、日期类型等

4.2 在Controller中使用

java
@RestController
@RequestMapping("/user")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/export")
    public void export(HttpServletResponse response) throws IOException {
        // 获取用户列表
        List<User> userList = userService.list();
        
        // 转换为Excel数据模型
        List<UserExcel> excelList = userList.stream()
            .map(user -> {
                UserExcel excel = new UserExcel();
                BeanUtils.copyProperties(user, excel);
                return excel;
            })
            .collect(Collectors.toList());
        
        // 导出Excel
        ExcelUtils.exportExcel(response, "用户列表", UserExcel.class, excelList);
    }
}
  • 直接调用 ExcelUtils.exportExcel() 方法
  • 传入响应对象、文件名、数据类型和数据集合

4.3 前端调用示例

javascript
// 直接下载
window.location.href = '/user/export';

// 或使用axios下载
axios({
    url: '/user/export',
    method: 'GET',
    responseType: 'blob'
}).then(response => {
    const blob = new Blob([response.data], { type: 'application/vnd.ms-excel' });
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = '用户列表.xlsx';
    document.body.appendChild(a);
    a.click();
    window.URL.revokeObjectURL(url);
    document.body.removeChild(a);
});

5. 配置说明

5.1 依赖配置

pom.xml 中添加 EasyExcel 依赖:

xml
<dependency>
    <groupId>cn.idev</groupId>
    <artifactId>easy-excel</artifactId>
    <version>1.0.0</version>
</dependency>

5.2 其他依赖

  • Hutool JSON: 用于异常处理时的JSON序列化
  • Servlet API: 用于HTTP响应处理

6. 注意事项

  1. 方法调用限制

    • 该方法不能与返回值为 Result 的方法一起使用 AOP 日志记录,否则会报错:java.lang.IllegalStateException: getOutputStream() has already been called for this response
    • 原因是 AOP 日志记录可能会提前获取响应输出流
  2. 数据量限制

    • 建议单次导出数据量不超过10万条,否则可能导致内存溢出
    • 大数据量导出建议使用分页查询或异步导出
  3. 数据类型支持

    • 支持基本数据类型、日期类型、字符串类型等
    • 复杂对象需要转换为简单对象后导出
  4. 文件名规范

    • 文件名不能包含特殊字符,如 \/:*?"<>|
    • 建议使用中文或英文文件名,避免使用其他语言
  5. 浏览器兼容性

    • 支持主流浏览器,包括 Chrome、Firefox、Safari、Edge
    • IE浏览器可能需要特殊处理

7. 扩展建议

  1. 添加导入功能

    • 实现 Excel 导入功能,支持从 Excel 读取数据并保存到数据库
    • 支持导入模板下载和数据验证
  2. 支持多种导出格式

    • 支持导出为 CSV、PDF 等格式
    • 提供格式选择功能
  3. 自定义样式支持

    • 支持自定义表头样式、内容样式、边框样式等
    • 支持条件样式,如根据数值范围显示不同颜色
  4. 大数据量导出

    • 实现异步导出,支持百万级数据导出
    • 提供导出进度查询和下载链接
  5. 多工作表支持

    • 支持在一个 Excel 文件中导出多个工作表
    • 每个工作表可以有不同的数据和样式
  6. 导出模板支持

    • 支持根据模板导出数据
    • 支持在模板中指定占位符,动态替换数据
  7. 列选择功能

    • 支持用户选择需要导出的列
    • 支持保存用户的列选择配置

9. 常见问题排查

9.1 导出文件损坏

问题:导出的Excel文件无法打开,提示文件损坏

可能原因

  • 响应头设置错误
  • 输出流未正确关闭
  • 数据格式错误

解决方案

  • 检查响应头设置是否正确
  • 确保 autoCloseStream(true) 配置正确
  • 检查数据类型是否与Excel模型匹配

9.2 文件名乱码

问题:导出的文件名显示乱码

可能原因

  • 字符编码设置错误
  • 浏览器兼容性问题

解决方案

  • 确保 response.setCharacterEncoding("utf-8") 已设置
  • 确保文件名使用 URLEncoder.encode() 编码

9.3 导出速度慢

问题:导出大量数据时速度很慢

可能原因

  • 数据量过大
  • 未使用分页查询
  • 数据转换耗时

解决方案

  • 减少单次导出数据量
  • 使用分页查询获取数据
  • 优化数据转换逻辑

9.4 内存溢出

问题:导出大量数据时出现内存溢出

可能原因

  • 数据量超过JVM内存限制
  • 未使用流式导出

解决方案

  • 增加JVM内存
  • 使用EasyExcel的流式导出功能
  • 实现异步导出