EasyPOI
Easypoi的目标不是替代poi,而是让一个不懂导入导出的快速使用poi完成Excel和word的各种操作,而不是看很多api才可以完成这样工作。
开发目的
- 不太熟悉poi的
- 不想写太多重复太多的
- 只是简单的导入导出的
- 喜欢使用模板的
- 都可以使用easypoi
导入依赖
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.1.0</version>
</dependency>
或SpringBoot依赖
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.1.0</version>
</dependency>
Excel注解
属性 | 类型 | 类型 | 说明 |
---|---|---|---|
name | String | null | 列名 |
needMerge | boolean | fasle | 纵向合并单元格 |
orderNum | String | “0” | 列的排序,支持name_id |
replace | String[] | {} | 值得替换 导出是{a_id,b_id} 导入反过来 |
savePath | String | “upload” | 导入文件保存路径 |
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[] | {} | 合并单元格依赖关系,比如第二列合并是基于第一列 则{1}就可以了 |
mergeVertical | boolean | fasle | 纵向合并内容相同的单元格 |
注解方式导出
实体类:必须要有空构造函数,否则会报错“对象创建错误”
@Data
@Table(name="tb_user")
public class User {
@Id
@KeySql(useGeneratedKeys = true)
@Excel(name = "编号", orderNum = "0", width = 5)
private Long id; //主键
@Excel(name = "员工名", orderNum = "1", width = 15)
private String userName; //员工名
@Excel(name = "手机号", orderNum = "2", width = 15)
private String phone; //手机号
@Excel(name = "省份名", orderNum = "3", width = 15)
private String province; //省份名
@Excel(name = "城市名", orderNum = "4", width = 15)
private String city; //城市名
@Excel(name = "工资", orderNum = "5", width = 10)
private Integer salary; // 工资
@JsonFormat(pattern="yyyy-MM-dd")
@Excel(name = "入职日期", format = "yyyy-MM-dd",orderNum = "6", width = 15)
private Date hireDate; // 入职日期
private String deptId; //部门id
@Excel(name = "出生日期", format = "yyyy-MM-dd",orderNum = "7", width = 15)
private Date birthday; //出生日期
@Excel(name = "照片", orderNum = "10",width = 15,type = 2)
private String photo; //一寸照片
@Excel(name = "现在居住地址", orderNum = "9", width = 30)
private String address; //现在居住地址
private List<Resource> resourceList; //办公用品
}
使用EasyPOI方式导出
public void downLoadWithEasyPOI(HttpServletResponse response) throws Exception {
//文件名,sheet名,文件类型
ExportParams exportParams = new ExportParams("员工信息列表","数据", ExcelType.XSSF);
List<User> userList = userMapper.selectAll();
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, User.class, userList);
//4.下载
//一个流两个头
String fileName = "POI数据导出.xlsx";
response.setHeader("content-disposition","attachment;filename="+new String(fileName.getBytes(),"ISO8859-1"));
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//执行
workbook.write(response.getOutputStream());
}
注解方式导入
将刚导出的数据库导入到表中
Excel导入时需要的参数类ImportParams常用设置说明:
- 读取指定的sheet,比如要读取上传得第二个sheet 需要把startSheetIndex = 1
- 读取几个sheet,比如读取前2个sheet,sheetNum=2
- 读取第二个到第五个sheet,设置startSheetIndex = 1 然后sheetNum = 4
- 读取全部的sheet sheetNum 设置大点就可以了
- 保存Excel 设置 needVerfiy = true,默认保存的路径为upload/excelUpload/Test/yyyyMMddHHmss 保存名称上传时间五位随机数 如果自定义路径 修改saveUrl ,同时saveUrl也是图片上传时候的保存的路径
- 判断一个Excel是不是合法的Excel,importFields 设置值,表示表头必须至少包含的字段,如果缺一个就是不合法的excel不导入
- 图片的导入,导入的配置和导出是一样的,但是需要设置保存路径,设置保存路径saveUrl 默认为"upload/excelUpload" 可以手动修改 ImportParams 修改下就可以了
实体类:
@Data
@Table(name="tb_user")
public class User {
@Id
@KeySql(useGeneratedKeys = true) //主键
//不添加@Excel注解不导出,,isImportField = "true"是否依据注解导入
@Excel(name="编号",orderNum = "0",width = 5)
private Long id;
@Excel(name="员工姓名",orderNum = "1",width = 15,isImportField = "true")
private String userName; //员工名
@Excel(name="手机号",orderNum = "2",width = 15,isImportField = "true")
private String phone; //手机号
@Excel(name="省份",orderNum = "3",width = 15,isImportField = "true")
private String province; //省份名
@Excel(name="城市",orderNum = "4",width = 15,isImportField = "true")
private String city; //城市名
@Excel(name="工资",orderNum = "5",width = 10,type = 10,isImportField = "true")
private Integer salary; // 工资
@Excel(name="入职日期",orderNum = "6",width = 15,format = "yyyy-MM-dd",isImportField = "true")
@JsonFormat(pattern="yyyy-MM-dd")
private Date hireDate; // 入职日期
//和表属性不对应
@Transient
//转json不考虑这个字段
@JsonIgnore
private String hireDateStr; // 入职日期-字符串格式
private String deptId; //部门id
@Excel(name="出生日期",orderNum = "7",width = 15,format = "yyyy-MM-dd",isImportField = "true")
private Date birthday; //出生日期
//savePath = ""图片存放路径
@Excel(name="图片",orderNum = "9",width = 15,type = 2,isImportField = "true",savePath = "D:\\java\\idea\\IdeaProject2\\user_management\\src\\main\\resources\\static\\user_photos")
private String photo; //一寸照片
@Excel(name="现住址",orderNum = "8",width = 20,isImportField = "true")
private String address; //现在居住地址
private List<Resource> resourceList; //办公用品
@Override
public String toString() {
return "User{" +
"id=" + id +
", userName='" + userName + '\'' +
'}';
}
}
easyPOI导入数据
/**
* 使用easyPOI方式导入数据
*/
public void uploadExcelWithEasyPOI(MultipartFile file) throws Exception {
ImportParams importParams = new ImportParams();
importParams.setNeedSave(false);//是否需要保存
importParams.setTitleRows(1);//大标题占多少行
importParams.setHeadRows(1);//小标题占多少行
//输入流,指定类型
List<User> userList = ExcelImportUtil.importExcel(file.getInputStream(),User.class,importParams);
for (User user : userList) {
//数据库中已有id,新增主键报错
user.setId(null);
userMapper.insert(user);
}
}
根据模板导出数据
采用的写法是{{}}代表表达式,然后根据表达式里面的数据取值,easypoi不会改变excel原有的样式
模板样式:
/**
* 使用EasyPOI,根据模板导出数据
* @param id
* @param response
*/
public void downLoadUserInfoByTemplateEasyPOI(Long id, HttpServletResponse response) throws Exception {
//1.读取模板
//获取项目的根目录,创建目录---获取绝对路径
File rootPath = new File(ResourceUtils.getURL("classpath:").getPath());
File templateFile = new File(rootPath.getAbsolutePath(), "/excel_template/userInfo3.xlsx");
//用来做导出的param,模板地址,是否遍历sheet
TemplateExportParams exportParams = new TemplateExportParams(templateFile.getPath(),true);
User user = userMapper.selectByPrimaryKey(id);
//处理图片
ImageEntity imageEntity = new ImageEntity();
//图片路径
imageEntity.setUrl(rootPath+user.getPhoto());
//设置图片-铺满--占几行,占几列
imageEntity.setColspan(2);
imageEntity.setRowspan(4);
//设置宽,高
//imageEntity.setWidth(50);
//imageEntity.setHeight(100);
Map<String, Object> map = EntityUtils.entityToMap(user);
map.put("photo",imageEntity);
//导出
Workbook workbook = ExcelExportUtil.exportExcel(exportParams,map);
//4.下载
//一个流两个头
String fileName = "EasyPOI用户数据导出.xlsx";
response.setHeader("content-disposition","attachment;filename="+new String(fileName.getBytes(),"ISO8859-1"));
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//执行
workbook.write(response.getOutputStream());
}
导出CSV
CsvExportParams 的参数描述如下:
属性 | 类型 | 默认值 | 功能 |
---|---|---|---|
encoding | String | UTF8 | 文件编码 |
spiltMark | String | , | 分隔符 |
textMark | String | “ | 字符串识别,可以去掉,需要前后一致 |
titleRows | int | 0 | 表格头,忽略 |
headRows | int | 1 | 标题 |
exclusions | String[] | 0 | 忽略的字段 |
如果需要导出几百万数据时不可能全部加载到一个List中的,所以easyPOI的方式导出csv是支持不了太大的数据量的,如果导出几百万条数据还是得选择OpenCSV方式导出。
public void downLoadCSVByEasyPOI(HttpServletResponse response) throws Exception {
ServletOutputStream outputStream = response.getOutputStream();
//导出
String fileName = "csv数据导出.csv";
response.setHeader("content-disposition","attachment;filename="+new String(fileName.getBytes(),"ISO8859-1"));
response.setContentType("text/csv");
CsvExportParams csvExportParams = new CsvExportParams();
List<User> userList = userMapper.selectAll();
//参数,类型,数据,输出流User.class和excel共用的
//忽略到图片导出
csvExportParams.setExclusions(new String[]{"照片"});
CsvExportUtil.exportCsv(csvExportParams,User.class,userList,outputStream);
}
导出word(docx)
仅仅支持07版本的word也是只能生成后缀是docx的文档。
列举下EasyPoi支持的指令以及作用,最主要的就是各种fe的用法:
三元运算 {{test ? obj:obj2}}
n: 表示 这个cell是数值类型 {{n:}}
le: 代表长度{{le:()}} 在if/else 运用{{le:() > 8 ? obj1 : obj2}}
fd: 格式化时间 {{fd:(obj;yyyy-MM-dd)}}
fn: 格式化数字 {{fn:(obj;###.00)}}
fe: 遍历数据,创建row
!fe: 遍历数据不创建row
$fe: 下移插入,把当前行,下面的行全部下移.size()行,然后插入
#fe: 横向遍历
v_fe: 横向遍历值
!if: 删除当前列 {{!if:(test)}}
单引号表示常量值 ‘’ 比如’1’ 那么输出的就是 1
&NULL& 空格
&INDEX& 表示循环中的序号,自动添加
]] 换行符 多行遍历导出
sum: 统计数据
模板
public void downloadContractByEasyPOI(Long id, HttpServletResponse response) throws Exception {
//获取模板文档
//获取项目的根目录,创建目录---获取绝对路径
File rootPath = new File(ResourceUtils.getURL("classpath:").getPath());
File templateFile = new File(rootPath.getAbsolutePath(), "word_template/contract_template2.docx");
//准备数据
User user = this.findById(id);
//数据转map
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("userName",user.getUserName());
hashMap.put("hireDate",simpleDateFormat.format(user.getHireDate()));
hashMap.put("address",user.getAddress());
ImageEntity imageEntity = new ImageEntity();
imageEntity.setUrl(rootPath+user.getPhoto());
//System.out.println("用户图片"+rootPath+user.getPhoto());
imageEntity.setHeight(100);
imageEntity.setWidth(50);
hashMap.put("picture",imageEntity);
//resourceList转map
List<Map> resourceMapList = new ArrayList<>();
Map<String,Object> map = null;
for (Resource resource : user.getResourceList()) {
map = new HashMap<>();
map.put("name",resource.getName());
map.put("price",resource.getPrice());
map.put("needReturn",resource.getNeedReturn());
//图片处理---在表格中做不到,需要POI
ImageEntity image = new ImageEntity();
image.setUrl(templateFile+"/static/"+resource.getPhoto());
map.put("photo",image);
resourceMapList.add(map);
}
hashMap.put("resourceList",resourceMapList);
//模板文档结合数据--产生新的文档
XWPFDocument document = WordExportUtil.exportWord07(templateFile.getPath(), hashMap);
//4.导出word
String fileName = "员工"+user.getUserName()+"合同.docx";
response.setHeader("content-disposition","attachment;filename="+new String(fileName.getBytes(),"ISO8859-1"));
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
document.write(response.getOutputStream());
}
结果:表格中的图片需要POI来做
word转pdf
1.环境准备:本机上安装了2007以上的office软件 ,jdk1.6以上的版本
2.下载jar包:地址
3.将jar放入本地仓库,进入到jar所在的目录执行以下命令:
mvn install:install-file -DgroupId=com.jacob -DartifactId=jacob -Dversion=1.19 -Dfile=jacob.jar -Dpackaging=jar
4.把dll文件放入到 jre\bin 目录下(64位的放x64文件,32位的放x86文件)
添加依赖
<dependency>
<groupId>com.jacob</groupId>
<artifactId>jacob</artifactId>
<version>1.9</version>
</dependency>
测试代码
package com.itheima.demo;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
public class JacobDemo {
public static void main(String[] args) {
String source = "D:\\李四_合同.docx";
String target = "D:\\李四_合同.pdf";
System.out.println("Word转PDF开始启动...");
ActiveXComponent app = null;
try {
// 调用window中的程序
app = new ActiveXComponent("Word.Application");
// 调用的时候不显示窗口
app.setProperty("Visible", false);
// 获得所有打开的文档
Dispatch docs = app.getProperty("Documents").toDispatch();
Dispatch doc = Dispatch.call(docs, "Open", source).toDispatch();
System.out.println("转换文档到PDF:" + target);
// 另存为,将文档保存为pdf,其中Word保存为pdf的格式宏的值是17
Dispatch.call(doc, "SaveAs", target, 17);
Dispatch.call(doc, "Close");
} catch (Exception e) {
System.out.println("Word转PDF出错:" + e.getMessage());
} finally {
// 关闭office
if (app != null) {
app.invoke("Quit", 0);
}
}
}
}
Excel操作其他文章
EasyExcel的使用
POI操作Excel
POI操作word及百万数据导入导出