1. easyexcel–100M
EasyExcel是一个基于Java的使用简单、节省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
节省内存的原因:在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析
EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理
通过Java代码完成对Excel的读写操作。所谓的读写理解为上传和下载
github地址:https://github.com/alibaba/easyexcel
官方文档:https://www.yuque.com/easyexcel/doc
2. easyexcel写操作
所谓的写操作,就是把Java中的类对象写入到excel表格中
实现步骤
- 引入依赖
<dependency>
<groupId>repMaven.com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>
-
封装相应的对象,创建与表格对应的实体类
@Data @AllArgsConstructor @NoArgsConstructor public class ExcelDemo { @ExcelProperty(value = "姓名")//标记excel的表头内容 public String name; @ExcelProperty(value = "年龄") public Integer age; @ExcelProperty(value = "性别") public String sex; @ExcelIgnore//写入excel表格时忽略该属性 public String address; }
- @ExcelProperty:标记excel的表头内容
- @ExcelIgnore:在写入excel表格时忽略该属性
-
通过easyexcel完成写入操作
public class WriteExcel { public static void main(String[] args) { //fileName:表示excel写入的路径以及名称 String fileName="D:\\idea\\easyexcel_demo1\\writer.xlsx"; //这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板,然后文件流会自动关闭 //如果这里使用03,则 传入 excelType 参数即可 List<ExcelDemo> list=new ArrayList<>(); list.add(new ExcelDemo("章三",18,"男","郑州")); list.add(new ExcelDemo("李斯",19,"男","郑州")); list.add(new ExcelDemo("汪芜",20,"女","郑州")); list.add(new ExcelDemo("码字",25,"男","郑州")); EasyExcel.write(fileName,ExcelDemo.class).sheet("第一次完成写操作").doWrite(list); } }
- 准备文件路径
- 写出文件
3. easyexcel写操作——web模式【导出】
导出:需要将数据库里面的文件以附件的形式下载到本地电脑,需要参数为response对象,返回值类型为void
- 实例
@Controller
public class ExcelController {
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
List<ExcelDemo> list=new ArrayList<>();
list.add(new ExcelDemo("章三",18,"男","郑州"));
list.add(new ExcelDemo("李斯",19,"男","郑州"));
list.add(new ExcelDemo("汪芜",20,"女","郑州"));
list.add(new ExcelDemo("码字",25,"男","郑州"));
EasyExcel.write(response.getOutputStream(), ExcelDemo.class).sheet("模板").doWrite(list);
}
}
也可以在controllre层仅进行调用操作,将逻辑交由service去做,即:
- controller
@ApiOperation("导出")
@GetMapping("/download")
public void exportData(HttpServletResponse response){
dictService.exportData(response);
}
- service
@Override
public void exportData(HttpServletResponse response) {
try {
//设置相关参数
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("数据字典", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");
//获取文件
List<Dict> list = this.baseMapper.selectList(null);
//转换文件
ArrayList<DictEeVo> dictEeVos = new ArrayList<>();
for (Dict dict : list) {
DictEeVo dictEeVo = new DictEeVo();
//转换
BeanUtils.copyProperties(dict, dictEeVo);
//添加
dictEeVos.add(dictEeVo);
}
//写出
EasyExcel.write(response.getOutputStream(), DictEeVo.class).sheet("数据字典").doWrite(dictEeVos);
} catch (Exception e) {
e.printStackTrace();
}
}
测试
测试仅需允许项目,然后在前端页面写入实际的url地址即可,也可以添加按钮的点击事件进行测试
4. easyexcel读操作
- 流程
- 实现步骤
-
引入fastjson依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency>
com.alibaba.fastjson.JSON
是阿里巴巴开源的一个高性能数据交换格式库,它是基于Java语言的JSON解析和生成工具。Fastjson旨在提供一种快速、便捷的方式来序列化和反序列化Java对象到JSON字符串,以及将JSON字符串转换回Java对象。它支持大数据量的处理,并且具有优秀的性能,通常比标准的Java自带的java.util.JSONObject
和org.json.JSONObject
更快。使用Fastjson的好处包括:
- 高效:通过字节码操作,使得JSON解析和生成的速度非常快。
- 易用:API设计简洁明了,易于理解和上手。
- 功能丰富:支持复杂数据结构的处理,如日期、数组、集合等。
在Java项目中,你可以通过Maven或Gradle添加fastjson依赖来使用它,然后通过
JSONObject
、JSONArray
或其他类来进行JSON相关的操作。 -
创建监听器
package com.zmq.excel; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.util.ListUtils; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import java.util.List; // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去 @Slf4j public class DemoDataListener implements ReadListener<ExcelDemo> { /** * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收 */ private static final int BATCH_COUNT = 100; /** * 缓存的数据 */ private List<ExcelDemo> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); /** * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。 */ private DemoDAO demoDAO; public DemoDataListener() { // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数 demoDAO = new DemoDAO(); } /** * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来 * * @param demoDAO */ public DemoDataListener(DemoDAO demoDAO) { this.demoDAO = demoDAO; } /** * 这个每一条数据解析都会来调用 * * @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()} * @param context */ //一行一行的去读取里面的数据 @Override public void invoke(ExcelDemo data, AnalysisContext context) { log.info("解析到一条数据:{}", JSON.toJSONString(data)); cachedDataList.add(data); // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM if (cachedDataList.size() >= BATCH_COUNT) { saveData(); // 存储完成清理 list cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); } } /** * 所有数据解析完成了 都会来调用 * * @param context */ @Override public void doAfterAllAnalysed(AnalysisContext context) { // 这里也要保存数据,确保最后遗留的数据也存储到数据库 saveData(); log.info("所有数据解析完成!"); } /** * 加上存储数据库 */ private void saveData() { log.info("{}条数据,开始存储数据库!", cachedDataList.size()); demoDAO.save(cachedDataList); log.info("存储数据库成功!"); } }
进行读操作时就会触发监听器,基本不需要改动
-
dao
package com.zmq.excel; import java.util.List; /** * 假设这个是你的DAO存储。当然还要这个类让spring管理,当然你不用需要存储,也不需要这个类。 **/ public class DemoDAO { public void save(List<ExcelDemo> list) { // 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入 } }
dao中填写需要的操作
-
读取
public class ReadExcel { public static void main(String[] args) { /** * 指定列的下标或者列名 * * <p>1. 创建excel对应的实体对象,并使用{@link ExcelProperty}注解. 参照{@link IndexOrNameData} * <p>2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link IndexOrNameDataListener} * <p>3. 直接读即可 */ //fileName:表示excel读取的路径以及名称 String fileName="D:\\idea\\easyexcel_demo1\\writer.xlsx"; // 这里默认读取第一个sheet //new DemoDataListener():监听器 EasyExcel.read(fileName, ExcelDemo.class, new DemoDataListener()).sheet().doRead(); } }
5. easyexcel文件上传-web【导入】
导入:需要将本地文件插入到数据库,参数:multiparefile,返回值:“成功或失败”
使用excel进行导入需要解析器的配合,使用监听器对读取的文件进行操作
解析器:用来读取文件,并将数据插入到数据库
-
加入文件上传的依赖
<dependency> <groupId>repMaven.commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency>
commons-fileupload是一个开源库,专为Java应用程序设计,用于处理文件上传功能。它简化了处理HTTP请求中的multipart/form-data格式,这种格式通常用于用户通过Web表单上传文件到服务器。该库提供了一组工具类和处理器,使得开发者能够解析上传的文件流,并管理文件名、大小限制等复杂操作。它的API易于使用,支持断点续传以及错误处理,广泛应用于web应用开发中的文件上传组件。
-
文件上传解析器——spring配置文件中
若使用springboot框架,仅引入上述依赖即可
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="1000000000"/> </bean>
-
controller
@Autowired private DemoDAO demoDAO; @PostMapping("/upload") @ResponseBody //将返回值转化为json格式 public String upload(MultipartFile file) throws IOException{ EasyExcel.read(file.getInputStream(), ExcelDemo.class, new DemoDataListener(demoDAO)).sheet().doRead(); return "success"; }
DemoDao层加入注入spring容器的注解:@Component
-
测试——使用postman完成测试