news 2026/4/25 10:51:01

java实现自定义注解导出excel

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
java实现自定义注解导出excel

结合Spring AOP (面向切面编程)Alibaba EasyExcel

EasyExcel 是阿里巴巴开源的工具,相比 Apache POI,它极其节省内存(基于流式读写),并且对注解支持非常好。


1. 引入依赖 (Maven)

pom.xml中引入 EasyExcel 和 Spring Boot AOP。

<dependencies><!-- Web 依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- AOP 依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- Alibaba EasyExcel (高性能 Excel 工具) --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.2</version><!-- 请检查最新版本 --></dependency><!-- Lombok (简化代码,可选) --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies>

2. 定义自定义注解@ResponseExcel

创建一个注解,用于标记 Controller 方法,告诉 AOP 这个接口需要导出 Excel。

packagecom.example.demo.annotation;importjava.lang.annotation.*;@Target(ElementType.METHOD)// 作用于方法@Retention(RetentionPolicy.RUNTIME)// 运行时有效@Documentedpublic@interfaceResponseExcel{// 导出的文件名StringfileName()default"data";// Sheet 名称StringsheetName()default"Sheet1";// 导出的实体类类型(用于解析表头)Class<?>clazz();}

3. 定义导出实体类 (Model)

使用 EasyExcel 提供的@ExcelProperty注解来定义表头。

packagecom.example.demo.model;importcom.alibaba.excel.annotation.ExcelIgnore;importcom.alibaba.excel.annotation.ExcelProperty;importcom.alibaba.excel.annotation.write.style.ColumnWidth;importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;importjava.util.Date;@Data@AllArgsConstructor@NoArgsConstructorpublicclassUserExcelVO{@ExcelProperty("用户ID")@ColumnWidth(20)privateLongid;@ExcelProperty("用户名")@ColumnWidth(30)privateStringusername;@ExcelProperty("年龄")privateIntegerage;@ExcelProperty("注册时间")@ColumnWidth(30)privateDatecreateTime;@ExcelIgnore// 忽略该字段,不导出privateStringpassword;}

4. 实现 AOP 切面处理逻辑 (核心)

这是整个功能的“大脑”。它拦截带有@ResponseExcel的方法,获取返回值(数据列表),然后直接写入 HttpServletResponse 流中。

packagecom.example.demo.aspect;importcom.alibaba.excel.EasyExcel;importcom.example.demo.annotation.ResponseExcel;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.springframework.stereotype.Component;importorg.springframework.web.context.request.RequestContextHolder;importorg.springframework.web.context.request.ServletRequestAttributes;importjavax.servlet.http.HttpServletResponse;importjava.net.URLEncoder;importjava.util.List;@Aspect@ComponentpublicclassExcelExportAspect{/** * 环绕通知 * 拦截被 @ResponseExcel 注解的方法 */@Around("@annotation(responseExcel)")publicObjectaround(ProceedingJoinPointpoint,ResponseExcelresponseExcel)throwsThrowable{// 1. 执行目标方法,获取返回的数据列表Objectresult=point.proceed();// 如果返回的不是 List,或者为空,则直接返回原结果(或抛出异常,视业务而定)if(!(resultinstanceofList)){returnresult;}List<?>dataList=(List<?>)result;// 2. 获取 Response 对象ServletRequestAttributesrequestAttributes=(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();if(requestAttributes==null){returnnull;}HttpServletResponseresponse=requestAttributes.getResponse();if(response==null){returnnull;}// 3. 设置响应头信息response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");// 防止中文乱码StringfileName=URLEncoder.encode(responseExcel.fileName(),"UTF-8").replaceAll("\\+","%20");response.setHeader("Content-Disposition","attachment;filename*=utf-8''"+fileName+".xlsx");// 4. 调用 EasyExcel 写入数据到流中try{EasyExcel.write(response.getOutputStream(),responseExcel.clazz()).sheet(responseExcel.sheetName()).doWrite(dataList);}catch(Exceptione){// 导出异常处理,比如重置 response 输出 JSON 错误信息response.reset();response.setContentType("application/json");response.setCharacterEncoding("utf-8");response.getWriter().println("{\"code\": 500, \"message\": \"导出Excel失败: "+e.getMessage()+"\"}");}// 5. 返回 null,因为数据已经写入 Response 流,不需要 Spring MVC 再处理返回值returnnull;}}

5. Controller 调用示例

现在,你只需要在 Controller 方法上加上@ResponseExcel即可实现导出,业务逻辑只需返回List

packagecom.example.demo.controller;importcom.example.demo.annotation.ResponseExcel;importcom.example.demo.model.UserExcelVO;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.ArrayList;importjava.util.Date;importjava.util.List;@RestController@RequestMapping("/excel")publicclassExcelController{/** * 导出用户列表 * 访问地址: http://localhost:8080/excel/export */@GetMapping("/export")@ResponseExcel(fileName="用户列表",sheetName="用户数据",clazz=UserExcelVO.class)publicList<UserExcelVO>exportUsers(){// 模拟查询数据库获取数据List<UserExcelVO>list=newArrayList<>();list.add(newUserExcelVO(1L,"张三",20,newDate(),"123"));list.add(newUserExcelVO(2L,"李四",25,newDate(),"456"));list.add(newUserExcelVO(3L,"王五",30,newDate(),"789"));// 直接返回 List 数据即可,AOP 会自动接管导出逻辑returnlist;}}

注意事项:

  1. 返回类型:被注解的方法必须返回List<T>类型的数据,否则 AOP 可能会抛错或忽略。
  2. JDK 8 兼容性:EasyExcel 和上述代码完全兼容 JDK 8。
  3. 文件名乱码:代码中使用了URLEncoder.encode(..., "UTF-8")并设置了filename*=utf-8'',这是标准的 HTTP 协议写法,能兼容绝大多数现代浏览器下载中文文件不乱码。
  4. 大数据量导出
    • 上面的代码是一次性把 List 加载到内存。如果你要导出 10 万行以上的数据,建议修改 Controller 和 AOP 逻辑,使其支持分页查询写入(doWrite可以多次调用),或者直接在 AOP 中接受Collection。EasyExcel 本身是流式的,只要你不把百万条数据一次性new出来放到 List 里,它就不会 OOM。
  5. 前端联调:前端调用此接口时,需要将responseType设置为blob,否则下载的文件可能是乱码字符串。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 0:31:33

基于SpringBoot的车辆报废回收系统(毕业设计项目源码+文档)

课题摘要 在机动车报废回收行业规范化、数字化升级的背景下&#xff0c;传统车辆报废回收模式存在 “流程审批繁琐、车辆溯源难、数据统计滞后、监管透明度低” 的痛点&#xff0c;难以满足车主便捷报废、企业高效运营、监管部门精准管控的需求。基于 SpringBoot 的车辆报废回收…

作者头像 李华
网站建设 2026/4/22 4:20:02

租用日本服务器价格便宜的原因

在 2026 年的海外服务器租赁市场中&#xff0c;日本服务器呈现出 “高配置 低门槛” 的独特优势&#xff0c;更关键的是&#xff0c;低价并未牺牲核心品质 ——90% 以上服务商提供 NTT/KDDI 原生 IP、CN2 GIA 直连线路&#xff0c;稳定性与纯净度远超同价位其他地区服务器。这…

作者头像 李华
网站建设 2026/4/25 0:15:31

数据结构:广义表

广义表 资料&#xff1a;https://pan.quark.cn/s/43d906ddfa1b、https://pan.quark.cn/s/90ad8fba8347、https://pan.quark.cn/s/d9d72152d3cf 一、广义表的定义 广义表&#xff08;Generalized List&#xff09;是线性表的扩展&#xff0c;是由零个或多个原子&#xff08;Atom…

作者头像 李华
网站建设 2026/4/25 5:10:31

Linux进程间通信内存映射(mmap)实现篇

Linux 内核中 mmap 的实现(基于 2.6.12) 概述 基于 2.6.12 内核, 说明 mmap 系统调用的核心数据结构、系统调用路径及关键实现. 主要文件: mm/mmap.c、mm/msync.c、mm/filemap.c、include/linux/mm.h、include/linux/mman.h. 核心数据结构 mm_struct (进程地址空间描述符) // i…

作者头像 李华
网站建设 2026/4/25 5:16:34

a5 4444444444

444444444444444444

作者头像 李华