JAVA解析Excel工具EasyExcel
官方讲解:Java解析、生成Excel比较有名的框架有Apache poi、jxl。
但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API
可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版
Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。
easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI
sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,
并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,
在上层做了模型转换的封装,让使用者更加简单方便
Ps: 64M内存20秒读取75M(46W行25列)的Excel(3.0.2+版本)
版本支持
2+ 版本支持 Java7和Java6
3+ 版本至少 Java8
maven依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <!-- EasyExcel --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.0.5</version> </dependency>
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>4.1.2</version> </dependency>
|
实体类
1.实体类
注解:
1.@Data -> lombok插件 注解 使用之后自动生成属性的get/set方法
2.@AllArgsConstructor -> lombok插件 注解 使用之后生成全部的构造方法不含无参构造
3.@NoArgsConstructor -> lombok插件 注解 使用之后生成无参构造
4.@ExcelProperty(value = “Excel标题名称”) -> easyExcel 注解
5.@ColumnWidth(35) -> easyExcel 注解 列宽
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| /** * @Author jiushiboy * @Date 2021/11/22 15:36 * @Version 1.0 */
@Data @AllArgsConstructor @NoArgsConstructor public class JiuShiBoy{ @ExcelProperty(value = "年龄") @ColumnWidth(35) private Integer age; @ExcelProperty(value = "名称") @ColumnWidth(35) private String name;
@ExcelProperty(value = "邮箱") @ColumnWidth(35) private String email; }
|
封装EasyExcel工具类(百度找的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| import com.alibaba.excel.EasyExcel; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener;
import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List;
/** * 高性能处理Excel工具类 * * @author jiushiboy * */ public class EasyExcelUtil { /** * 使用 模型 来读取Excel * * @param inputStream Excel的输入流 * @param clazz 模型的类 * @return 返回 模型 的列表 */ public static <T> List<T> readExcel(InputStream inputStream, Class<T> clazz) { ModelExcelListener<T> listener = new ModelExcelListener<T>(); EasyExcel.read(inputStream, clazz, listener).sheet().doRead(); return listener.getDatas(); }
/** * 使用 模型 来导出到WEB * * @param response web的响应 * @param data 要写入的以 模型 为单位的数据 * @param fileName 配置Excel的表名 * @param sheetName 配置Excel的页签名 * @param clazz 模型的类 * @throws IOException */ public static <T> void writeExcel(HttpServletResponse response, List<T> data, Class<T> clazz, String fileName, String sheetName) throws IOException { // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(data); }
/** * 使用 模型 来写入Excel * <br/>注意,如果是web输出流,需要设置头 * * @param outputStream Excel的输出流 * @param data 要写入的以 模型 为单位的数据 * @param sheetName 配置Excel的表名字 * @param clazz 模型的类 */ public static <T> void writeExcel(OutputStream outputStream, List<T> data, Class<T> clazz, String sheetName) { EasyExcel.write(outputStream, clazz).sheet(sheetName).doWrite(data); }
/** * 模型 解析监听器 */ private static class ModelExcelListener<T> extends AnalysisEventListener<T> { private List<T> datas = new ArrayList<>();
@Override public void invoke(T object, AnalysisContext context) { datas.add(object); }
@Override public void doAfterAllAnalysed(AnalysisContext context) { }
public List<T> getDatas() { return datas; } }
}
|
导入控制层Controller
注解:
@Api(value = “swagger插件上显示的注释”)
@RestController -> SpringBoot注解 = @ResponseBody + @Controller
@RequestMapping(“/easyExcelImportController”) -> Spring注解 请求接口路径需要加上注解中定义的值 假设 localhost:8080/easyExcelImportController
@Slf4j 日志注解 当类上定义此注解则会打印日志,使用 log.info(“这里是日志:{}”,”这个入参是object 一般会将入参通过FastJson转json传入JsonObject.toJsonString(object)”);
@ApiParam(“file) swagger注解
@RequestPart(“file”) Spring注解 主要接收表单数据
HttpServletRequest 代表客户端请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @Api(value = "swagger上显示的注释") @RestController @RequestMapping("/easyExcelImportController") @Slf4j public class TargetManageController {
@ApiOperation(value = "excel导入操作", notes = "excel导入操作") @PostMapping(value = "/importing", consumes = "multipart/*", headers = "content-type=multipart/form-data") public void importing(@ApiParam(name = "file", value = "导入的文件", required = true) @RequestPart("file") MultipartFile file, HttpServletRequest request) { try { importService.importing(file); } catch (Exception | IOException e) { log.error("导入数据出现异常:{}", e.getMessage()); } }
@ApiOperation(value = "excel导出", notes = "excel导出") @RequestMapping(value = "/leadingOut") public void leadingOut(HttpServletResponse response) { try { List<JiuShiBoy> result = targetMangeService.leadingOut(); EasyExcelUtil.writeExcel(response, result, JiuShiBoy.class, "jiushiboy", "sheet1"); } catch (IOException e) { log.error("导出出现异常:{}", e); } } }
|
导入Service 业务层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| /** * @Author wenchang * @Date 2021/11/16 10:19 * @Version 1.0 */ @Service @RefreshScope @Slf4j public class ImportService { /*** * @description: 导入演示 * @param: file * @date: 2022/01/28 17:24 */ public void importing(MultipartFile file) throws IOException { // 使用工具类直接转成类型数据 参数一:输入流对象 参数二:转成什么对象类型 List<JiuShiBoy> targetExcelManages = EasyExcelUtil.readExcel(file.getInputStream(), JiuShiBoy.class); // 然后就随便你操作咯 } /*** * @description: 导出演示 * @date: 2022/01/28 17:24 */ public List<JiuShiBoy> leadingOut() { // 这里我就不弄数据了 返回数据之后看Controller return new ArrayList<JiuShiBoy>(); } }
|