官方文档: http://easypoi.mydoc.io/
pom.xml
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.0.0</version>
</dependency>
工具类
import cn.afterturn.easypoi.word.WordExportUtil;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.util.Assert;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Map;
public class ExportWordUtils {
/**
* 导出word
* <p>
* 第一步生成替换后的word文件,只支持docx
* </p>
* <p>
* 第二步下载生成的文件
* </p>
* <p>
* 第三步删除生成的临时文件
* </p>
* 模版变量中变量格式:{{foo}}
*
* @param templatePath word模板地址
* @param fileName 文件名
* @param params 替换的参数
* @param request HttpServletRequest
* @param response HttpServletResponse
*/
public static void exportWord(String templatePath, String fileName, Map<String, Object> params,
HttpServletRequest request, HttpServletResponse response) {
Assert.notNull(templatePath, "模板路径不能为空");
Assert.notNull(fileName, "导出文件名不能为空");
Assert.isTrue(fileName.endsWith(".docx"), "word导出请使用docx格式");
try {
String userAgent = request.getHeader("user-agent").toLowerCase();
if (userAgent.contains("msie") || userAgent.contains("like gecko")) {
fileName = URLEncoder.encode(fileName, "UTF-8");
} else {
fileName = new String(fileName.getBytes("utf-8"), "ISO-8859-1");
}
XWPFDocument doc = WordExportUtil.exportWord07(templatePath, params);
//文本换行
for(XWPFTable table : doc.getTables()) {//表格
for(XWPFTableRow row : table.getRows()) {//行
for(XWPFTableCell cell : row.getTableCells()) {//单元格 : 直接cell.setText()只会把文字加在原有的后面,删除不了文字
addBreakInCell(cell);
}
}
}
// 设置强制下载不打开
response.setContentType("application/force-download");
// 设置文件名
response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
OutputStream out = response.getOutputStream();
doc.write(out);
out.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
// delAllFile(temDir);// 这一步看具体需求,要不要删
}
}
public static boolean delAllFile(String path) {
boolean flag = false;
File file = new File(path);
if (!file.exists()) {
return flag;
}
if (!file.isDirectory()) {
return flag;
}
String[] tempList = file.list();
File temp = null;
for (int i = 0; i < tempList.length; i++) {
if (path.endsWith(File.separator)) {
temp = new File(path + tempList[i]);
} else {
temp = new File(path + File.separator + tempList[i]);
}
if (temp.isFile()) {
temp.delete();
}
if (temp.isDirectory()) {
// 先删除文件夹里面的文件
delAllFile(path + File.separator + tempList[i]);
// 再删除空文件夹
delFolder(path + File.separator + tempList[i]);
flag = true;
}
}
return flag;
}
public static void delFolder(String folderPath) {
try {
// 删除完里面所有内容
delAllFile(folderPath);
String filePath = folderPath;
File myFilePath = new File(filePath);
myFilePath.delete(); // 删除空文件夹
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 设置换行
*
* @param value 需要换行的内容
* @param paragraph 当前段落
* @param run
*/
private static void setWrap(Object value, XWPFParagraph paragraph, XWPFRun run) {
if (((String) value).indexOf("\n") > 0) {
//设置换行
String[] text = value.toString().split("\n");
run = paragraph.insertNewRun(0);
for (int f = 0; f < text.length; f++) {
if (f == 0) {
run.setText(text[f].trim());
} else {
// run.addCarriageReturn();//硬回车
// 换行
run.addBreak();
run.setText(text[f].trim());
}
}
} else {
run.setText((String) value);
}
}
/**
* 文本换行
* @param cell
*/
private static void addBreakInCell(XWPFTableCell cell) {
if(cell.getText() != null && cell.getText().contains("\n")) {
for (XWPFParagraph p : cell.getParagraphs()) {
for (XWPFRun run : p.getRuns()) {//XWPFRun对象定义具有一组公共属性的文本区域
if(run.getText(0)!= null && run.getText(0).contains("\n")) {
String[] lines = run.getText(0).split("\n");
if(lines.length > 0) {
run.setText(lines[0], 0); // set first line into XWPFRun
for(int i=1;i<lines.length;i++){
// add break and insert new text
run.addBreak();//中断
// run.addCarriageReturn();//回车符,但是不起作用
run.setText(lines[i]);
}
}
}
}
}
}
}
}
添加word模板


前端
html
<el-button type="primary" size="mini" :loading="exportLoading" @click="exportData()">导出</el-button>
js
exportData() {
this.exportLoading = true
api.exportWordBook(this.query).then(res => {
const currentdate = '党支部工作手册-' + this.orgName + '.docx'
const blob = new Blob([res.data]) // 创建一个类文件对象:Blob对象表示一个不可变的、原始数据的类文件对象
const url = window.URL.createObjectURL(blob) // URL.createObjectURL(object)表示生成一个File对象或Blob对象
const dom = document.createElement('a') // 设置一个隐藏的a标签,href为输出流,设置download
dom.style.display = 'none'
dom.href = url
dom.setAttribute('download', currentdate) // 指示浏览器下载url,而不是导航到它;因此将提示用户将其保存为本地文件
document.body.appendChild(dom)
dom.click()
}).finally(() => {
this.exportLoading = false
})
}
后端
@GetResource(name = "导出world", path = "/branchWorkBook/exportWordBook")
public ResponseData exportBranchWordBook(BranchWorkBookRequest branchWorkBook) {
HttpServletResponse response = HttpServletUtil.getResponse();
HttpServletRequest request = HttpServletUtil.getRequest();
Map<String, Object> params = new HashMap<>();
String templatePath = "template/branchWorkBookTemplate.docx"; //模板路径
HrOrganizationExpand org = this.hrOrganizationExpandService.getHrOrganizationExpandByOrgId(branchWorkBook.getOrgId());
params.put("orgName",org.getFullName());
params.put("branchSecretaryEmploymentRecord1","学习工作经历相关内容。。。。");//生成文件名
Long time = System.currentTimeMillis();
// 生成的word格式
String formatSuffix = ".docx";
// 拼接后的文件名
String fileName = time + formatSuffix;//文件名 带后缀
//导出word
ExportWordUtils.exportWord(templatePath, fileName, params, request, response);
return new SuccessResponseData();
}