简介
easypoi功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员,就可以方便的写出Excel导出,Excel模板导出,Excel导入,word模板导出,通过简单的注解和模板 语言(熟悉的表达式语法),完成以前复杂的写法
使用easypoi
环境搭建:
1.导入依赖
<!--引入easypoi的依赖-->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>3.2.0</version>
</dependency>
- 1.easypoi 父包—作用大家都懂得
- 2.easypoi-annotation 基础注解包,作用于实体类对象上,拆分后方便maven多工程的依赖管理
- 3.easypoi-base 导入导出的工具包,可以完成excel导出、导入,word的导出,Excel的导出等功能
- 4.easy-web耦合了spring-mvc,基于AbstractView,极大简化了spring-mvc下的导出功能
- 5.sax导入使用xercesImpl这个包(这个包可能造成奇怪的问题哈),word导出使用poi-scratchpad,都作为可选包了
相关注解
easypoi起因就是Excel的导出和导入,最初的模板是实体和Excel的对应,model-row,filed-col这样利用注解我们可以很容易做到excel导入导出
# 1.注解说明
2.easypoi起因就是Excel的导出导入,最初的模板是实体类和Excel的对应,model--row,filed--col 这样利用注解我们可以很容易做到excel导入导出。经过了一段时间的发展,现有注解的5个类分别是
- @Excel 作用到filed上面,是对Excel-列的一个描述
- @ExcelCollection 表示一个集合,主要针对一对多的导出,比如一个老师对应多个科目,这个科目就可以用集合表示
- @ExcelEntity 表示一个继续深入导出的实体,但是他没有太多的实际意义,只是告诉系统这个对象里面同样有导出的字段
-
- @Excellgnore 和名字一样表示这个字段被忽略跳出这个导入导出
-
- @ExcelTarger 这个是作用于最外层的对象,描述这个对象的id,以便支持一个对象可以针对不同导出做不同处理
Excel附属属性:

2.编写如下测试类进行测试
用户类:
package com.cd.entity;
import cn.afterturn.easypoi.excel.annotation.*;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@ExcelTarget("users") // 代表导出这个类的导出对象的标识
public class User implements Serializable {
@Excel(name = "编号",orderNum = "0")
private Integer id;
// 将名字为c的替换成cd
@Excel(name = "姓名",orderNum = "1",replace = "cd_c")
private String name;
@Excel(name = "年龄",orderNum = "2")
private Integer age;
@Excel(name = "生日",width = 35.0,format = "yyyy-MM-dd HH:mm:ss",orderNum = "4")
private Date date;
@ExcelIgnore // 该字段不输入到表格中
private List<String> habbys; // 爱好
@Excel(name = "爱好",width = 20.0,orderNum = "3")
private String habbyStr;
@ExcelEntity // 表示一对一关系
private Card card;
@ExcelCollection(name = "订单列表",orderNum = "8")
private List<Order> orders; // 表示一对多关系
@Excel(name = "头像",width = 20,height = 20,type = 2) // type = 2代表为图片类型
private String photo;
public String getHabbyStr() {
StringBuilder sb = new StringBuilder();
habbys.forEach(e->{
sb.append(e).append("-");
});
return sb.toString();
}
public void setHabbyStr(String habbyStr) {
this.habbyStr = habbyStr;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public List<String> getHabbys() {
return habbys;
}
public void setHabbys(List<String> habbys) {
this.habbys = habbys;
}
public Card getCard() {
return card;
}
public void setCard(Card card) {
this.card = card;
}
public List<Order> getOrders() {
return orders;
}
public void setOrders(List<Order> orders) {
this.orders = orders;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", date=" + date +
'}';
}
}
身份证类
package com.cd.entity;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import java.io.Serializable;
@ExcelTarget("card")
public class Card implements Serializable {
@Excel(name = "身份证号码",width = 20.0,orderNum = "6")
private String no;
@Excel(name = "籍贯",orderNum = "7")
private String address;
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Card{" +
"no='" + no + '\'' +
", address='" + address + '\'' +
'}';
}
}
订单类
package com.cd.entity;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import java.io.Serializable;
@ExcelTarget("orders")
public class Order implements Serializable {
@Excel(name = "订单标号",orderNum = "8",width = 20.0)
private String no; // 订单标号
@Excel(name = "订单名称",orderNum = "9",width = 15.0)
private String name; // 订单名称
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Order(String no, String name) {
this.no = no;
this.name = name;
}
public Order() {
}
@Override
public String toString() {
return "Order{" +
"no='" + no + '\'' +
", name='" + name + '\'' +
'}';
}
}
测试类如下
package com.cd;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import com.cd.entity.Card;
import com.cd.entity.Order;
import com.cd.entity.User;
import org.apache.poi.ss.usermodel.Workbook;
import org.junit.Test;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
public class TestPOI {
// 模拟数据库查询所有记录
public List<User> getUsers(){
List<User> userList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setId(i);
user.setAge(10+i);
user.setDate(new Date());
user.setName("小陈—"+i);
Card card = new Card();
card.setAddress("湖北省咸宁市咸安区");
card.setNo("45845434");
user.setHabbys(Arrays.asList("唱歌,跳舞,rap"));
// 订单信息
List<Order> orders = new ArrayList<>();
orders.add(new Order("12","超短裙"));
orders.add(new Order("12","超短连衣裙"));
orders.add(new Order("12","超超短连衣裙"));
user.setOrders(orders);
user.setPhoto("C:\\Users\\xwsjhp007\\Pictures\\Saved Pictures\\1122.jpg");
userList.add(user);
}
return userList;
}
// 导出excel
@Test
public void testExport() throws IOException {
// 获取数据
List<User> users = getUsers();
// 导出excel
// 参数1:exportParams 导出配置对象 参数2:导出的类型 参数3:导出的数据集合
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("用户信息列表", "用户信息"), User.class, users);
// 将excel写入指定位置
FileOutputStream fileOutputStream = new FileOutputStream("D:\\easypoitest\\poi.xlsx");
// 写入输出流
workbook.write(fileOutputStream);
// 关流
fileOutputStream.close();
workbook.close();
}
}
运行结果如图所示

大数据量导出
- 说明:大数据导出是当我们导出数据量在几万到上百万条数据时,一次从数据库中查询这么多数据加载到内存然后写入会对我们的内存和CPU产生都产生压力,这个时候需要我们像分页一样导出分段写入Excel缓解Excel的压力
Workbook workbook =ExcelExporterUtil.exportBigExcel(new ExportParams("用户列表","测试"),User.class,getUser());
workbook.write(outputStream);
ExcelExportUtil.closeExportBigExcel();
注意:最好大量数据进行分页处理,每次导出的数据量最好不要超过1w条记录
导入EXcel
1.选取一个excel表格文件,里面内容如下

- 编写实体类字段,和表格中的属性一一对应
package com.cd.entity;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import java.util.Date;
@ExcelTarget("emp")
public class Emp {
@Excel(name = "编号")
private String id;
@Excel(name = "姓名")
private String name;
@Excel(name = "年龄")
private Integer age;
@Excel(name = "爱好")
private String like;
@Excel(name = "生日",format = "yyyy-MM-dd HH:mm:ss")
private Date bir;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getLike() {
return like;
}
public void setLike(String like) {
this.like = like;
}
public Date getBir() {
return bir;
}
public void setBir(Date bir) {
this.bir = bir;
}
@Override
public String toString() {
return "Emp{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", like='" + like + '\'' +
", bir=" + bir +
'}';
}
}
3.编写测试类
@Test
public void testImport() throws Exception {
// 参数1:导入excel文件流 参数2:导入类型 参数3:导入的配置对象
ImportParams importParams = new ImportParams();
importParams.setTitleRows(1); // 设置标题列占几行
importParams.setHeadRows(2); // 设置字段名称占几行 即header
importParams.setStartSheetIndex(0); // 设置从第几张表格开始读取,这里0代表第一张表,默认从第一张表读取
importParams.setImportFields(new String[]{"编号"}); // 表示导入的表格中至少含有编号这个字段才算是一个合法的表格,否则报错
List<Emp> emps = ExcelImportUtil.importExcel(new FileInputStream("D:\\easypoitest\\poi.xlsx"), Emp.class, importParams);
emps.forEach(System.out::println);
}
结果如下

导入小技巧
-
读取指定的sheet
比如要读取上传得第二个sheet,那摩需要把startSheetIndex = 1就可以了 -
读取几个sheet
比如要读取两个sheet,那摩sheetNum = 2 就可以了 -
读取第二个到第五个sheet
设置 startSheetIndex = 1 然后sheetNum = 4 -
读取全部的sheet
sheetNum 设置大点就ok了 -
判断一个Excel是不是合法的Excel
importFields设置下值,就是表示表头必须至少包含的字段,如果缺少一个就不是合法的Excel,不导入,就会报错
SpringBoot+mybatis+easyexcel搭建
1.导入如下依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cd</groupId>
<artifactId>springboot-easypoi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-easypoi</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--引入mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
<!--引入easypoi-->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>3.2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.编写application.properties配置文件如下
erver.port=8989
spring.application.name=easypoi
spring.thymeleaf.cache=false
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/easypoi?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
mybatis.type-aliases-package=com.cd.pojo
mybatis.mapper-locations=classpath:/mapper/*.xml
# 打印数据库层的日志
logging.level.com.cd.dao=debug
#upload.dir=E:/springboot-easypoi/src/main/resources/static/img
#spring.resources.static-locations=classpath:/static/,file:${upload.dir}
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=100MB
3.该案例使用模板引擎为thymeleaf,导入了如下静态资源文件

前端页面代码如下
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"/>
<title>导入excel的主页面</title>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<h1>选择Excel文件导入到数据中</h1>
<form th:action="@{/import}" method="post" enctype="multipart/form-data" class="form-inline">
<div class="form-group">
<input class="form-group" type="file" name="excelFile">
<input type="submit" class="btn btn-danger" value="导入数据">
</div>
</form>
</div>
<div class="col-md-12">
<h1>显示导入数据列表</h1>
<table class="table table-bordered">
<tr>
<th>编号</th>
<!-- <th>头像</th>-->
<th>姓名</th>
<th>生日</th>
<th>爱好</th>
<th>身份证号码</th>
<th>家庭住址</th>
</tr>
<tr th:each="user : ${users}">
<td th:text="${user.id}">1</td>
<!-- <td><img th:src="${user.photo}" style="height: 40px" alt=""> </td>-->
<td th:text="${user.name}">小陈</td>
<td th:text="${#dates.format(user.bir,'yyyy-MM-dd')}">2021-7-12</td>
<td th:text="${user.habbys}">篮球</td>
<td th:text="${user.no}">23</td>
<td th:text="${user.address}">23</td>
</tr>
</table>
<hr>
<a th:href="@{/export}" class="btn btn-info">导出Excel</a>
</div>
</div>
</div>
<script th:src="@{/js/jquery-3.3.1.min.js}" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" crossorigin="anonymous"></script>
<script th:src="@{/js/bootstrap.min.js}" crossorigin="anonymous"></script>
</body>
</html>
4.实体类
package com.cd.pojo;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelIgnore;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import java.io.Serializable;
import java.util.Date;
@ExcelTarget("users")
public class User implements Serializable {
@Excel(name = "编号")
private String id;
@Excel(name = "姓名")
private String name; // 姓名
@Excel(name = "生日",format = "yyyy-MM-dd HH:mm:ss")
private Date bir; // 生日
@Excel(name = "爱好")
private String habbys; // 爱好
@Excel(name = "身份证号码")
private String no; // 生分证号码
@Excel(name = "籍贯")
private String address; // 地址
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBir() {
return bir;
}
public void setBir(Date bir) {
this.bir = bir;
}
public String getHabbys() {
return habbys;
}
public void setHabbys(String habbys) {
this.habbys = habbys;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", bir=" + bir +
", habbys='" + habbys + '\'' +
", no='" + no + '\'' +
", address='" + address + '\'' +
'}';
}
}
dao层接口
package com.cd.dao;
import com.cd.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.stereotype.Component;
import java.util.List;
@Mapper
@Component
public interface UserDao {
// 查询所有用户
List<User> findAll();
// 添加用户
void save(User user);
//
}
对应mapper层xml文件 (UserDaoMapper.xml)
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cd.dao.UserDao">
<!--查询所有-->
<select id="findAll" resultType="User">
select id,name,bir,habbys,no,address from t_user
</select>
<!--插入用户信息-->
<insert id="save" parameterType="User" useGeneratedKeys="true" keyProperty="id">
insert into t_user values (#{id},#{name},#{bir},#{habbys},#{no},#{address})
</insert>
</mapper>
service层接口 (UserService.java)
package com.cd.service;
import com.cd.pojo.User;
import java.util.List;
public interface UserService {
// 查询所有用户
List<User> findAll();
// 导入用户
void save(List<User> users);
}
实现类(UserServiceImpl.java)
package com.cd.service;
import com.cd.dao.UserDao;
import com.cd.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public List<User> findAll() {
return userDao.findAll();
}
@Override
public void save(List<User> users) {
users.forEach(user -> {
user.setId(null);
userDao.save(user);
});
}
}
controller层(IndexController)
package com.cd.controller;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.cd.pojo.User;
import com.cd.service.UserService;
import org.apache.commons.codec.net.URLCodec;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
@Controller
public class IndexController {
private static final Logger log = LoggerFactory.getLogger(IndexController.class);
@Autowired
private UserService userService;
@RequestMapping("/index")
public String index(){
return "index";
}
/**
* 导入excel表格数据
* @return
*/
@PostMapping("/import")
public String importExcel(MultipartFile excelFile) throws Exception {
log.info("文件名:{}",excelFile.getOriginalFilename());
// excel导入
ImportParams params = new ImportParams();
params.setTitleRows(1);// 设置标题列占几行
params.setHeadRows(1);// 设置字段名称占几行 即header
// 参数1:导入excel文件流 参数2:导入类型 参数3:导入的配置对象
List<User> users = ExcelImportUtil.importExcel(excelFile.getInputStream(), User.class, params);
userService.save(users);
return "redirect:/findAll";
}
/**
* 导出excel文件
* @param response
*/
@RequestMapping("/export")
public void exportExcel(HttpServletResponse response) throws IOException {
// 查询数据库中的所有数据
List<User> users = userService.findAll();
// 生成excel
// 参数1:exportParams 导出配置对象,该对象需传递标题名称和第一张sheet名称(二者都是自定义取名字)
// 参数2:导出的类型 参数3:导出的数据集合
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("用户列表信息", "用户信息"), User.class, users);
// 设置响应输出流,web端下载
response.setHeader("content-disposition","attachment;fileName="+ URLEncoder.encode("用户列表.xls","UTF-8"));
// 获取响应输出流
ServletOutputStream outputStream = response.getOutputStream();
workbook.write(outputStream);
outputStream.close();
workbook.close();
}
@RequestMapping("/findAll")
public String findAll(Model model){
List<User> users = userService.findAll();
model.addAttribute("users",users);
return "index";
}
}
数据库字段如下:

启动项目,访问localhost:8989/index:结果如下所示:

点击选择文件,选择一个excel表格,点击导入数据,其中这里导入的excel表格内容如下

导入之后结果如下

对应的数据库中的数据也会增加,同理,点击导出表格,导出的表格内容如下:

本文详细介绍了Easypoi库在Java中的使用,包括环境搭建、注解说明、Excel导出导入示例,以及如何处理大数据量导出。通过Easypoi,可以方便地实现Excel和实体类之间的映射,简化了数据操作。同时,文章展示了SpringBoot整合Mybatis和Easypoi实现Excel导入导出的完整流程。
2733

被折叠的 条评论
为什么被折叠?



