前言
使用
-
easypoi父包
-
easypoi-annotation基础注解包,作用与实体对象上,拆分后方便maven多工程的依赖管理;
-
easypoi-base导入导出工具包,可以完成excel导出、导入,word导出导入;
-
easypoi-web耦合了spring-mvc基于abstractview,极大简化了spring-mvc下的导出功能;
-
sax导入使用xercesImpl这个包(这个包可能有问题),word导出使用poi-scratchpad,都已作为可选包
maven坐标如下
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.2.0</version>
</dependency>
简单使用
- 搭建项目maven
Easypoi注解
Excel导入导出
Excel的导入导出是Easypoi的核心功能,前期基本也是围绕这个打造的,主要分为三种方式的处理,其中模板和Html目前只支持导出,因为支持Map.class其实导入应该是怎样都支持的
- 注解方式,注解变种方式
- 模板方式
- Html方式
下面分别就这三种方式进行讲解
注解
注解介绍
easypoi起因就是Excel的导入导出,最初的模板是实体和Excel的对应,model–row,filed–col 这样利用注解我们可以和容易做到excel到导入导出
目前注解有五类分别为:
- @Excel 作用到filed上面,是对Excel一列的一个描述
- @ExcelCollection 表示一个集合,主要针对一对多的导出,eg一个教师对应多个科目,科目就可以用集合表示
- @ExcelEntity 表示一个继续深入导出的实体,但无过多实际意义,只是告诉系统这个对象里同样有导出的字段
- @Excelgnore 和名字一样表示这个字段被忽略跳过这个导出
- @ExcelTarget 这个是作用于最外层的对象,描述这个对象的id,以便支持一个对象可以针对不同导出做出不同处理
@Excel参数
这个是必须使用的注解,如果需求简单只使用这一个注解也是可以的,涵盖了常用的Excel需求,需要大家熟悉这个功能,主要分为基础,图片处理,时间处理,合并处理几块,name_id是上面讲的id用法,这里就不累言了
属性 | 类型 | 默认值 | 功能 |
---|---|---|---|
name | String | null | 列名,支持name_id |
needMerge | boolean | fasle | 是否需要纵向合并单元格(用于含有list中,单个的单元格,合并list创建的多个row) |
orderNum | String | “0” | 列的排序,支持name_id |
replace | String[] | {} | 值得替换 导出是{a_id,b_id} 导入反过来 |
savePath | String | “upload” | 导入文件保存路径,如果是图片可以填写,默认是upload/className/ IconEntity这个类对应的就是upload/Icon/ |
type | int | 1 | 导出类型 1 是文本 2 是图片,3 是函数,10 是数字 默认是文本 |
width | double | 10 | 列宽 |
height | double | 10 | 列高,后期打算统一使用@ExcelTarget的height,这个会被废弃,注意 |
isStatistics | boolean | fasle | 自动统计数据,在追加一行统计,把所有数据都和输出 这个处理会吞没异常,请注意这一点 |
isHyperlink | boolean | false | 超链接,如果是需要实现接口返回对象 |
isImportField | boolean | true | 校验字段,看看这个字段是不是导入的Excel中有,如果没有说明是错误的Excel,读取失败,支持name_id |
exportFormat | String | “” | 导出的时间格式,以这个是否为空来判断是否需要格式化日期 |
importFormat | String | “” | 导入的时间格式,以这个是否为空来判断是否需要格式化日期 |
format | String | “” | 时间格式,相当于同时设置了exportFormat 和 importFormat |
databaseFormat | String | “yyyyMMddHHmmss” | 导出时间设置,如果字段是Date类型则不需要设置 数据库如果是string 类型,这个需要设置这个数据库格式,用以转换时间格式输出 |
numFormat | String | “” | 数字格式化,参数是Pattern,使用的对象是DecimalFormat |
imageType | int | 1 | 导出类型 1 从file读取 2 是从数据库中读取 默认是文件 同样导入也是一样的 |
suffix | String | “” | 文字后缀,如% 90 变成90% |
isWrap | boolean | true | 是否换行 即支持\n |
mergeRely | int[] | {} | 合并单元格依赖关系,比如第二列合并是基于第一列 则{0}就可以了 |
mergeVertical | boolean | fasle | 纵向合并内容相同的单元格 |
fixedIndex | int | -1 | 对应excel的列,忽略名字 |
isColumnHidden | boolean | false | 导出隐藏列 |
@ExcelTarget参数
限定一个到处实体的注解,以及一些通用设置,作用于最外面的实体
属性 | 类型 | 默认值 | 功能 |
---|---|---|---|
value | String | null | 定义ID |
height | double | 10 | 设置行高 |
fontSize | short | 11 | 设置文字大小 |
@ExcelEntity
标记是不是导出excel 标记为实体类,一遍是一个内部属性类,标记是否继续穿透,可以自定义内部id
属性 | 类型 | 默认值 | 功能 |
---|---|---|---|
id | String | null | 定义ID |
@ExcelCollection
一对多的集合注解,用以标记集合是否被数据以及集合的整体排序
属性 | 类型 | 默认值 | 功能 |
---|---|---|---|
id | String | null | 定义ID |
name | String | null | 定义集合列名,支持nanm_id |
orderNum | int | 0 | 排序,支持name_id |
type | Class<?> | ArrayList.class | 导入时创建对象使用 |
@ExcelIgnore
忽略这个属性,多使用需循环引用中,无需多解释吧^^,添加此注解后此元素不会被导出excel
导出
搭建一个简单的项目
新建实体类user
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import lombok.Data;
import java.util.Date;
import java.io.Serializable;
/**
* @author Hmoumou
*/
@Data
@ExcelTarget("users")
public class User implements Serializable {
@Excel(name = "身份标识")
private Integer id;
@Excel(name = "姓名")
private String name;
@Excel(name = "年龄")
private Integer age;
@Excel(name = "生日")
private Date dir;
}
新建测试类实现方法
package com.easypoiTry;
import static org.junit.Assert.assertTrue;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import com.easypoiTry.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;
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
// 模拟数据库记录
public List<User> getUsers(){
List<User> users = new ArrayList<>();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setId(i);
user.setName("Hmoumou_"+i);
user.setAge(20+i);
user.setDir(new Date());
if (i%2==0){
user.setStatus("1");
user.setHobby(Arrays.asList("睡觉","吃饭"));
}else{
user.setStatus("0");
user.setHobby(Arrays.asList("嫦娥","游泳"));
}
users.add(user);
}
return users;
}
// 导出excel表
@Test
public void testExport() throws IOException {
// 获取数据
List<User> users = getUsers();
// 导出excel
// 参数1excelParams:导出配置对象;参数2:导出的类型;参数3:导出的数据集合
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("用户列表测试", "用户信息"), User.class, users);
// 将excel写入指定位置
FileOutputStream outputStream = new FileOutputStream("C:\\Users\\H某人\\Desktop\\测试excel输出.xls");
workbook.write(outputStream);
outputStream.close();
workbook.close();
}
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}
导出list集合
默认样式如下
如果不想使用中括号,可以操作如下
@ExcelIgnore
private List<String> hobby;
@Excel(name = "爱好",width = 20.0,orderNum = "5")
private String hobbystr;
//可以通过hobbystr转换一下
public String getHobbystr() {
StringBuilder sb = new StringBuilder();
hobby.forEach(e->{
sb.append(e).append("、");
});
return sb.toString();
}
一对一关系对象导入
package com.easypoiTry.entity;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import lombok.Data;
import java.io.Serializable;
@Data
@ExcelTarget("cards")
public class Card implements Serializable {
@Excel(name = "身份证号码",width = 30.0,orderNum = "6")
private String cardId;
@Excel(name = "地址",width = 40.0,orderNum = "7")
private String address;
}
package com.easypoiTry.entity;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelEntity;
import cn.afterturn.easypoi.excel.annotation.ExcelIgnore;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import lombok.Data;
import java.util.Date;
import java.io.Serializable;
import java.util.List;
/**
* @author Hmoumou
*/
@Data
@ExcelTarget("users")
public class User implements Serializable {
@Excel(name = "身份标识",orderNum = "0")
private Integer id;
@Excel(name = "姓名",orderNum = "1")
private String name;
// suffix添加后缀
@Excel(name = "年龄",orderNum = "3",suffix = "岁")
private Integer age;
// width是输出时excel的列宽设置,orderNum是输出顺序
@Excel(name = "生日",width = 20.0,orderNum = "2",format = "yyyy-MM-dd HH:mm:ss")
private Date dir;
//replace中利用前值替换后值
@Excel(name = "状态",replace = {"注册_1","未注册_0"},orderNum = "4")
private String status;
// @Excel(name = "爱好",orderNum = "5",width = 20.0)
@ExcelIgnore
private List<String> hobby;
@Excel(name = "爱好",width = 20.0,orderNum = "5")
private String hobbystr;
public String getHobbystr() {
StringBuilder sb = new StringBuilder();
hobby.forEach(e->{
sb.append(e).append("、");
});
return sb.toString();
}
@ExcelEntity //标识一对一关系
private Card card;
}
package com.easypoiTry;
import static org.junit.Assert.assertTrue;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import com.easypoiTry.entity.Card;
import com.easypoiTry.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;
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
// 模拟数据库记录
public List<User> getUsers(){
List<User> users = new ArrayList<>();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setId(i);
user.setName("Hmoumou_"+i);
user.setAge(20+i);
user.setDir(new Date());
Card card = new Card();
card.setCardId("428758188805984585");
card.setAddress("遍地是家");
user.setCard(card);
if (i%2==0){
user.setStatus("1");
user.setHobby(Arrays.asList("睡觉","吃饭"));
}else{
user.setStatus("0");
user.setHobby(Arrays.asList("嫦娥","游泳"));
}
users.add(user);
}
return users;
}
// 导出excel表
@Test
public void testExport() throws IOException {
// 获取数据
List<User> users = getUsers();
// 导出excel
// 参数1excelParams:导出配置对象;参数2:导出的类型;参数3:导出的数据集合
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("用户列表测试", "用户信息"), User.class, users);
// 将excel写入指定位置
FileOutputStream outputStream = new FileOutputStream("C:\\Users\\H某人\\Desktop\\测试excel输出.xls");
workbook.write(outputStream);
outputStream.close();
workbook.close();
}
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}
一对多集合导出
图片导出
// type为2才能被是被为图片显示
@Excel(name = "头像信息",orderNum = "9",width = 60.0,height = 60.0,type = 2,imageType = 1)
private String photo;
大数据导出
使用exportBigExcel
导入
简单导入实现
创建对应实体类
package com.easypoiTry.entity;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@ExcelTarget("imps")
public class emp implements Serializable {
@Excel(name = "编号")
private String id;
@Excel(name = "姓名")
private String name;
@Excel(name = "生日")
private Date bir;
@Excel(name = "年龄")
private Integer age;
@Excel(name = "状态",replace = {"激活_1","锁定_0"})
private String status;
}
写测试类
//导入普通数据
@Test
public void testImport() throws Exception {
ImportParams params = new ImportParams();
params.setTitleRows(1);
params.setHeadRows(1);
List<emp> emps = ExcelImportUtil.importExcel(new FileInputStream("C:\\Users\\H某人\\Desktop\\导入测试数据.xls"), emp.class, params);
emps.forEach(System.out::println);
}
导入技巧
springboot项目实战
初始化项目
新建springboot项目
引入相关依赖
- mybatis
- mysql
- druid
- easypoi
- thymeleaf
- lombok
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 引入相关依赖-->
<!-- 引入mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<!-- 引入mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 引入druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>
<!-- 引入thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- easyPOI依赖引入-->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.2.0</version>
</dependency>
编写配置文件application.yml
server:
port: 8989
spring:
thymeleaf:
cache: false
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/easypoi?serverTimezone=CTT&useUnicode=true&characterEncoding=utf-8
username: root
password: root
application:
name: easypoi
mybatis:
mapper-locations: classpath:com/easypoitry/easypoi_springboot/mapper/*.xml
type-aliases-package: com.easypoi.easypoi_springboot.entity
项目结构
简易前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<h1>选择Excel文件导入到数据中</h1>
<form action="" method="POST" class="form-inline">
<div class="form-group">
<input type="file" class="form-control" 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>
</tr>
<tr>
<td>1</td>
<td><img src="" alt=""></td>
<td>Hmouren</td>
<td>23</td>
<td>2021.01.01</td>
</tr>
<tr>
<td>1</td>
<td><img src="" alt=""></td>
<td>Hmouren</td>
<td>23</td>
<td>2021.01.01</td>
</tr>
</table>
<hr>
<input type="button" class="btn btn-info" value="导出excel">
</div>
</div>
</div>
</body>
</html>
建库建表
/*
Navicat MySQL Data Transfer
Source Server : 201705092006
Source Server Version : 50726
Source Host : localhost:3306
Source Database : easypoi
Target Server Type : MYSQL
Target Server Version : 50726
File Encoding : 65001
Date: 2021-01-06 16:19:52
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`bir` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`habbys` varchar(255) DEFAULT NULL,
`no` varchar(255) DEFAULT NULL,
`photo` varchar(255) DEFAULT NULL,
`address` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_user
-- ----------------------------