环境介绍
技术栈 |
springboot+mybatis-plus+mysql+easyexcel |
软件 |
版本 |
mysql |
8 |
IDEA |
IntelliJ IDEA 2022.2.1 |
JDK |
1.8 |
Spring Boot |
2.7.13 |
mybatis-plus |
3.5.3.2 |
EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。
他能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。
官网https://easyexcel.opensource.alibaba.com/
加入依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.3.2</version> </dependency>
读Excel
- 编写实体类
@TableName(value ="product") @Data @NoArgsConstructor @AllArgsConstructor public class Product implements Serializable { /** * 序号 */ @TableId(type = IdType.AUTO) @ExcelProperty("序号") private Integer number; /** * 创建时间 */ @ExcelProperty("创建时间") private Date createtime; /** * 产品名称 */ @ExcelProperty("产品名称") private String productname; /** * 产品编号 */ @ExcelProperty("产品编号") private String productnumber; /** * 产品型号 */ @ExcelProperty("产品型号") private String manufacturer; /** * 产品位置 */ @ExcelProperty("产品位置") private String producepath; /** * 图片位置 */ @ExcelProperty("图片位置") private String imagepath; /** * 使用单位 */ @ExcelProperty("使用单位") private String unit; /** * 金额 */ @ExcelProperty("金额") private Integer money; /** * 入库时间 */ @ExcelProperty("入库时间") private Date intime; /** * 出库时间 */ @ExcelProperty("出库时间") private Date puttime; /** * 操作人 */ @ExcelProperty("操作人") private String operator; /** * 创建人 */ @ExcelProperty("创建人") private String createduser; /** * 备注 */ @ExcelProperty("备注") private String notes; /** * 产品数量 */ @ExcelProperty("产品数量") private Integer producedigit; /** * 产品单位 */ @ExcelProperty("产品单位") private String productunit; @TableField(exist = false) private static final long serialVersionUID = 1L; }
- 监听器
使用官方默认提供的监听器
- 调用API
@Test public void simpleRead() { //String fileName = TestFileUtil.getPath() + "simpleWriteTest1702391756908.xlsx"; String fileName = "C:\\Users\\1111\\Desktop\\simpleWriteTest1702391756908.xlsx"; // 这里默认每次会读取100条数据 然后返回过来 直接调用使用数据就行 // 具体需要返回多少行可以在`PageReadListener`的构造函数设置 EasyExcel.read(fileName, Product.class, new PageReadListener<Product>(dataList -> { for (Product product : dataList) { System.out.println(product); //log.info("读取到一条数据{}", JSON.toJSONString(product)); } })).sheet().doRead(); }
写Excel
TestFileUtil工具类
public class TestFileUtil { public static InputStream getResourcesFileInputStream(String fileName) { return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); } public static String getPath() { return TestFileUtil.class.getResource("/").getPath(); } public static TestPathBuild pathBuild() { return new TestPathBuild(); } public static File createNewFile(String pathName) { File file = new File(getPath() + pathName); if (file.exists()) { file.delete(); } else { if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } } return file; } public static File readFile(String pathName) { return new File(getPath() + pathName); } public static File readUserHomeFile(String pathName) { return new File(System.getProperty("user.home") + File.separator + pathName); } /** * build to test file path **/ public static class TestPathBuild { private TestPathBuild() { subPath = new ArrayList<>(); } private final List<String> subPath; public TestPathBuild sub(String dirOrFile) { subPath.add(dirOrFile); return this; } public String getPath() { if (CollectionUtils.isEmpty(subPath)) { return TestFileUtil.class.getResource("/").getPath(); } if (subPath.size() == 1) { return TestFileUtil.class.getResource("/").getPath() + subPath.get(0); } StringBuilder path = new StringBuilder(TestFileUtil.class.getResource("/").getPath()); path.append(subPath.get(0)); for (int i = 1; i < subPath.size(); i++) { path.append(File.separator).append(subPath.get(i)); } return path.toString(); } } }
- 实体类编写
@TableName(value ="product") @Data @NoArgsConstructor @AllArgsConstructor public class Product implements Serializable { /** * 序号_自动生成 */ @TableId(type = IdType.AUTO) @ExcelProperty("序号") private Integer number; /** * 创建时间 */ @ExcelProperty("创建时间") private Date createtime; /** * 产品名称 */ @ExcelProperty("产品名称") private String productname; /** * 产品编号 */ @ExcelProperty("产品编号") private String productnumber; /** * 产品型号 */ @ExcelProperty("产品型号") private String manufacturer; /** * 产品位置 */ @ExcelProperty("产品位置") private String producepath; /** * 图片位置 */ @ExcelProperty("图片位置") private String imagepath; /** * 使用单位 */ @ExcelProperty("使用单位") private String unit; /** * 金额 */ @ExcelProperty("金额") private Integer money; /** * 入库时间 */ @ExcelProperty("入库时间") private Date intime; /** * 出库时间 */ @ExcelProperty("出库时间") private Date puttime; /** * 操作人 */ @ExcelProperty("操作人") private String operator; /** * 创建人 */ @ExcelProperty("创建人") private String createduser; /** * 备注 */ @ExcelProperty("备注") private String notes; /** * 产品数量 */ @ExcelProperty("产品数量") private Integer producedigit; /** * 产品单位 */ @ExcelProperty("产品单位") private String productunit; @TableField(exist = false) private static final long serialVersionUID = 1L; }
- 数据生成方法
private List<Product> getData(int count) { List<Product> list = ListUtils.newArrayList(); for (int i = 0; i < count; i++) { Product product = new Product(); product.setCreatetime(new Date()); product.setProductname("服务器00"+i); product.setProductnumber(DigestUtils.md5Hex("hello"+i)); product.setManufacturer("huawei"); product.setProducepath("/test"); product.setImagepath("/test"); product.setIntime(new Date()); product.setOperator("张三"); product.setPuttime(new Date()); list.add(product); } return list; }
- 写入excel
@Test public void simpleWrite() { // 写法2 String fileName = TestFileUtil.getPath() + "simpleWriteTest" + System.currentTimeMillis() + ".xlsx"; // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 // 如果这里想使用03 则 传入excelType参数即可 EasyExcel.write(fileName, Product.class).sheet("测试01").doWrite(getData(10)); }
进阶
编写实体类
@TableName(value ="product") @Data @NoArgsConstructor @AllArgsConstructor public class Product implements Serializable { /** * 序号_自动生成 */ @TableId(type = IdType.AUTO) @ExcelProperty("序号") private Integer number; /** * 创建时间 */ @ExcelProperty("创建时间") private Date createtime; /** * 产品名称 */ @ExcelProperty("产品名称") private String productname; /** * 产品编号 */ @ExcelProperty("产品编号") private String productnumber; /** * 产品型号 */ @ExcelProperty("产品型号") private String manufacturer; /** * 产品位置 */ @ExcelProperty("产品位置") private String producepath; /** * 图片位置 */ @ExcelProperty("图片位置") private String imagepath; /** * 使用单位 */ @ExcelProperty("使用单位") private String unit; /** * 金额 */ @ExcelProperty("金额") private Integer money; /** * 入库时间 */ @ExcelProperty("入库时间") private Date intime; /** * 出库时间 */ @ExcelProperty("出库时间") private Date puttime; /** * 操作人 */ @ExcelProperty("操作人") private String operator; /** * 创建人 */ @ExcelProperty("创建人") private String createduser; /** * 备注 */ @ExcelProperty("备注") private String notes; /** * 产品数量 */ @ExcelProperty("产品数量") private Integer producedigit; /** * 产品单位 */ @ExcelProperty("产品单位") private String productunit; @TableField(exist = false) private static final long serialVersionUID = 1L; }
批量写数据
操作步骤:1、实体类(如上述实体类)
2、生成数据方法
private List<Product> getData(int count) { List<Product> list = ListUtils.newArrayList(); for (int i = 0; i < count; i++) { Product product = new Product(); product.setCreatetime(new Date()); product.setProductname("服务器00"+i); product.setProductnumber(DigestUtils.md5Hex("hello")); product.setManufacturer("huawei"); product.setProducepath("/test"); product.setImagepath("/test"); product.setIntime(new Date()); product.setOperator("张三"); product.setPuttime(new Date()); list.add(product); } return list; }
3、批量写如excel方法
/重复多次写入(写到单个或者多个Sheet) @Test public void manyWrite() { // 方法1: 如果写到同一个sheet String fileName = "C:\\Users\\13631\\Desktop\\simpleWriteTest1702391756908.xlsx"; // 这里 需要指定写用哪个class去写 try (ExcelWriter excelWriter = EasyExcel.write(fileName, Product.class).build()) { // 这里注意 如果同一个sheet只要创建一次 WriteSheet writeSheet = EasyExcel.writerSheet("测试").build(); long star = System.currentTimeMillis(); // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来 for (int i = 0; i < 5; i++) { // 分页去数据库查询数据 这里可以去数据库查询每一页的数据 List<Product> data = getData(1000); excelWriter.write(data, writeSheet); } long end = System.currentTimeMillis(); System.out.println("耗时:" + (end - star)/1000 + "秒"); } }
自定义模板写入excel
填充单行
填充集合
//根据模板填充数据 @Test public void fillWrite() { // 方案2 分多次 填充 会使用文件缓存(省内存) String fileName = "C:\\Users\\13631\\Desktop\\模板写数据.xlsx"; String templateFileName = "C:\\Users\\13631\\Desktop\\模板.xlsx"; try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) { WriteSheet writeSheet = EasyExcel.writerSheet().build(); excelWriter.fill(getData2(100), writeSheet); } }
填充效果
自定义监听器
1、实体类(如上述实体类)
2、自定义监听器
Invoke和doAfterAllAnalysed是必选的
public class MyListener implements ReadListener<Product> { private TestMapper testMapper; private ArrayList<Product> list = new ArrayList<>(); int sum=0; public MyListener(TestMapper testMapper) { this.testMapper = testMapper; } //每读一行,则调用该方法 @Override public void invoke(Product product, AnalysisContext analysisContext) { sum++; list.add(product); } //每读完整个excel,则调用该方法 @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { System.out.println("读取了"+sum+"行数据"); } }
@Test void contextLoads() { String fileName = "C:\\Users\\13631\\Desktop\\simpleWriteTest1702391756908.xlsx"; // 这里默认每次会读取100条数据 然后返回过来 直接调用使用数据就行 // 具体需要返回多少行可以在`PageReadListener`的构造函数设置 ExcelReader reader = EasyExcel.read(fileName, Product.class, new MyListener(new TestMapper())).build(); ReadSheet sheet = EasyExcel.readSheet().build(); reader.read(sheet); }