java使用easypoi导出为word文档
java使用easypoi导出word文档
环境:jdk1.8+springboot2.5.6+easypoi
EasyPoi官网:1. 前言 - Powered by MinDoc (wupaas.com),easypoi的easypoi-spring-boot-starter坐标,这里建议用4.4.0版本,使用官网中的4.0.0需要在yml中额外的配置。这里就使用4.4.0版本了
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
easypoi中的模板指令有
空格分割
三目运算 {{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: 统计数据
cal: 基础的+-X% 计算
dict: 字典
i18n: 国际化
代码中的word模板和图片位置截图如下
在springboot项目中,在static目录下的图片和视频文件都是可以通过url地址访问的,如果文件在其他位置,就需要我们自己进行静态资源映射的配置,具体看(2条消息) springboot静态资源映射配置_m0_62317155的博客-CSDN博客_springboot静态资源映射配置
word模板截图如下所示
这里使用word模板的形式,word模板如下图所示,使用{{}}在word中填写对应的map字段即可,如{{name}}。注意是英文状态下的输入法。这里的文字大小和颜色、字体等可以使用word和wps软件先在模板中设置好。
注意上图中的{{$fe: studentList t.name}}这里必须放在表格中,我试过了如果没有放在表格中代码会报错不生效,如果担心这里表格影响,可以使用word软件或者wps将word模板中的表格线去掉即可
https://plus.wps.cn/blog/p35884.html
Java代码
pom.xml
<?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.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>wordexport</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>wordexport</name>
<description>wordexport</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.4.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>
Controller
package com.example.controller;
import cn.afterturn.easypoi.entity.ImageEntity;
import cn.afterturn.easypoi.word.WordExportUtil;
import com.example.entity.Student;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/export")
public class ExportWordController {
@GetMapping("/exportword/{id}")
public void exportword(@PathVariable Integer id, HttpServletResponse response) throws Exception {
// 这里可以通过id查找数据库中保存的信息,这里就不查数据库了,大概数据数据测试就行了
Student student = new Student();
student.setId(id);
student.setName("罗辑");
student.setSex("男");
student.setNation("汉族");
student.setDescribe("我没有太多可说的,只有一个警告:生命从海洋登上陆地是地球生物进化的一个里程碑," +
"但那些上岸的鱼再也不是鱼了;同样,真正进入太空的人,再也不是人了,所以,人们,当你们打算飞向外太空再也不回头时," +
"请千万慎重,需付出的代价比你们想象的要大得多。" +
"我们都是阴沟里的虫子,但总还是得有人仰望星空。" +
"死亡是一座永恒的灯塔,不管你驶向何方,最终都会朝它转向。一切都将逝去,只有死神永生。");
student.setResource("翻阅坐标数据是歌者的工作,判断坐标的诚意是歌者的乐趣。");
// 读取word文档模板
// File filepath = new File("D:\\private\\javastudaykeshanchu\\javaweb\\wordexport\\src\\main\\resources\\templates\\exportword_template.docx");
File rootFile = new File((ResourceUtils.getURL("classpath:").getPath()));
File templateFile = new File(rootFile, "/templates/exportword_template.docx");
System.out.println(templateFile);
// 需要将bean转换为map集合
Map<String, Object> maps = new HashMap<>();
maps.put("name", student.getName());
maps.put("sex", student.getSex());
maps.put("nation", student.getNation());
maps.put("describe", student.getDescribe());
maps.put("resource", student.getResource());
// 写入图片
ImageEntity imageEntity = new ImageEntity();
// 这里可以是磁盘地址,也可以是对应的http地址,例如在springboot中static下的图片可以直接通过http的url访问。
imageEntity.setUrl("http://localhost:8080/img/1.jpg");
// 这里的宽高必须要设置
imageEntity.setWidth(500);
imageEntity.setHeight(300);
maps.put("photo",imageEntity);
ImageEntity imageEntity1 = new ImageEntity();
imageEntity1.setUrl("D:\\private\\javastudaykeshanchu\\javaweb\\wordexport\\src\\main\\resources\\static\\img\\2.jpg");
imageEntity1.setWidth(500);
imageEntity1.setHeight(300);
maps.put("photo1",imageEntity1);
// 这里以集合List的形式,在word模板中使用模板指令fe:遍历数据,创建row
List<Map<String,Object>> infoList = new ArrayList<>();
Map<String,Object> mapObj = null;
for (int i = 1; i <= 3; i++) {
mapObj = new HashMap<>();
ImageEntity imageEntity2 = new ImageEntity();
// 这里可以是磁盘地址,也可以是对应的http地址,例如在springboot中static下的图片可以直接通过http的url访问。
imageEntity2.setUrl("http://localhost:8080/img/" + i + ".jpg");
// 这里的宽高必须要设置
imageEntity2.setWidth(300);
imageEntity2.setHeight(200);
mapObj.put("imgurl",imageEntity2);
mapObj.put("name", "罗辑" + i);
infoList.add(mapObj);
}
maps.put("studentList", infoList);
String name = student.getName();
XWPFDocument word = WordExportUtil.exportWord07(templateFile.getPath(), maps);
String fileName = "三体资料(" + name + ")详情.docx";
response.setHeader("content-disposition", "attachment;filename=" + new String(fileName.getBytes(), "ISO8859-1"));
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
ServletOutputStream outputStream = response.getOutputStream();
word.write(outputStream);
outputStream.close();
word.close();
}
}
Entity
package com.example.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private Integer id;
private String name;
private String sex;
private String nation;
private String describe;
private String resource;
}
运行结果
在浏览器地址栏输入大概如下的地址http://localhost:8080/export/exportword/1,地址中的id为1是我随便输入的,这里之所以放id是因为在真实的开发中我们可以根据传入的id到对应的数据库表中查找到数据。我在代码中是自己懒得连数据库了,自己造了一个数据。具体看代码就行了。在浏览器输入的地址栏输入http://localhost:8080/export/exportword/1,即可下载一个word文档。将这个word文档打开之后得到如下的结果
代码中对应的字段和模板中对应的字段如下
最终的结果如下
跟前端代码联动
可以通过 window.location.href = "http://localhost:8080/export/exportword/1",调用对应的地址来实现导出word的功能。
使用window.location.href=url,window.open(url)也可以实现文件下载,但下载需要传请求头时,就不适用这种方法了。
参考文章:
(2条消息) vue前端调后台接口下载文件(get,post方法集合)爱写程序的小高的博客-CSDN博客vue调用下载文件接口
(2条消息) 下载Content-Type,Blob type类型汇总_爱写程序的小高的博客-CSDN博客
js下载doxc 文件示例和部分后缀对应的content-type 总结 - 天高任鸟飞吧 - 博客园 (cnblogs.com)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue简单页面试验</title>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<el-button type="primary" @click="daochuWord">导出为word</el-button>
<el-button type="primary" @click="daochuWord2">导出为word2</el-button>
<el-button type="primary" @click="daochuWord3">导出为word3</el-button>
<el-button type="primary" @click="daochuWord4">导出为word4</el-button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
},
methods: {
daochuWord() {
window.location.href = "http://localhost:8080/export/exportword/1"
},
daochuWord2() {
// 这个会闪一下就会关闭,暂时还在找办法解决中
window.open("http://localhost:8080/export/exportword/1")
},
// 这里使用了axios之后要注意了,注意看一下有没有配置axios的相应拦截器,这里因为是在线引入,所以没有配置响应拦截器。如果配置了响应拦截器,就要注意响应拦截器中是否是返回接口解构了axios的data的结果,这个一定要注意了。
daochuWord3() {
axios.get('http://localhost:8080/export/exportword/1', { responseType: "blob" }).then(res => {
debugger
const link = document.createElement("a");
let blob = new Blob([res.data], { type: "application/msword" });
link.style.display = "none";
link.href = URL.createObjectURL(blob);
link.setAttribute("download", '三体资料(罗辑)详情.docx');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
this.$message.success("导出成功")
})
},
async daochuWord4() {
const res = await axios.get('http://localhost:8080/export/exportword/1', { responseType: "blob" })
const link = document.createElement("a");
let blob = new Blob([res.data], { type: "application/msword" });
link.style.display = "none";
link.href = URL.createObjectURL(blob);
link.setAttribute("download", '三体资料(罗辑)详情.docx');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
this.$message.success("导出成功")
}
}
})
</script>
<style>
</style>
</body>
</html>
对应的html页面如下,点击对应的按钮就可以实现导出word文档了
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)