实际项目中,便于维护模板,采用直接 word里面制作占位符 来导出更为直观,而不是 将word做成tpl模板。
使用XWPFDocument (这种解析xlsx或者docx)和 HWPFDocument(这种解析xls或者doc)。 代码如下:
写磁盘代码:
点击查看代码
// 创建Word模板文件:在开始代码编写之前,我们需要准备一个Word模板文件,模板文件中的文本可以是固定的,也可以使用占位符来表示需要动态填充的内容
//读取Word模板文件
// 我们需要使用Apache POI库来读取Word模板文件,并将其加载到内存中进行后续的操作。代码如下
FileInputStream fis = null;
try {
File sPath = new File("D:/opt/jwxt/file/uploadfile/ly-edu-core-svc-thx/testWord.docx");
// File sPath = new File("/template/testword.doc");
fis = new FileInputStream(sPath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// HWPFDocument 支持doc XWPFDocument支持docx
XWPFDocument document = null;
FileOutputStream fos = null;
try {
document = new XWPFDocument(fis);
// } catch (IOException e) {
// e.printStackTrace();
// }
// 替换模板中的占位符
//在模板文件中,我们可以使用占位符来表示需要动态填充的内容,比如使用${placeholder}来表示占位符。我们需要遍历Word文档的所有段落和表格,找到包含占位符的位置,并将其替换为实际的内容。代码如下
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
String text = run.getText(0);
if (text != null && text.contains("${{成果名称}}")) {
text = text.replace("${{成果名称}}", "替换后的内容");
run.setText(text, 0);
}
}
}
// 表格处理方式
List<XWPFTable> tables = document.getTables();
for (XWPFTable table : tables) {
List<XWPFTableRow> rows = table.getRows();
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
List<XWPFParagraph> cellParagraphs = cell.getParagraphs();
for (XWPFParagraph cellParagraph : cellParagraphs) {
List<XWPFRun> runs = cellParagraph.getRuns();
for (XWPFRun run : runs) {
String text = run.getText(0);
if (text != null && text.contains("${{完成人姓名1}}")) {
text = text.replace("${{完成人姓名1}}", "替换后的内容");
run.setText(text, 0);
}
if (text != null && text.contains("${{成果名称}}")) {
text = text.replace("${{成果名称}}", "替换后的内容2222");
run.setText(text, 0);
}
}
}
}
}
}
// 导出word文档
File outFile = new File("D:\\opt\\jwxt\\file\\uploadfile\\ly-edu-core-svc-thx\\占位符完成打印.docx");
fos = new FileOutputStream(outFile);
} catch (Exception e) {
log.error( "获取word文档失败,原因是:" + e.getMessage());
} finally {
try {
document.write(fos);
if(fos != null) {
fos.close();
}
// document.close();
} catch (IOException e) {
e.printStackTrace();
}
}
与前端配合弹出流,使用response,代码如下
点击查看代码
/**
* 我们可以实现Java Word模板打印的功能。首先,我们需要引入Apache POI库,并创建一个Word模板文件。然后,我们需要读取模板文件并将其加载到内存中。
* 接下来,我们需要遍历Word文档,找到包含占位符的位置,并将其替换为实际的内容。最后,我们可以将生成的Word文档导出为文件。
* <p>
* 在实际应用中,我们可以根据具体需求扩展这个功能,比如支持更复杂的模板替换、添加图片和表格等。同时,我们也可以使用其他的库来实现类似的功能,比如Docx4j等
*
*
*/
@Autowired
private HttpServletResponse response;
@Autowired
private HttpServletRequest request;
@Override
public void testWordPrint(ReviewTemplateDto reviewTemplateDto) {
// 创建Word模板文件:在开始代码编写之前,我们需要准备一个Word模板文件,模板文件中的文本可以是固定的,也可以使用占位符来表示需要动态填充的内容
//读取Word模板文件
// 我们需要使用Apache POI库来读取Word模板文件,并将其加载到内存中进行后续的操作。代码如下
FileInputStream fis = null;
try {
File sPath = new File("D:/opt/jwxt/file/uploadfile/tt/模板.docx");
// File sPath = new File("/template/testword.doc");
fis = new FileInputStream(sPath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// HWPFDocument 支持doc XWPFDocument支持docx
XWPFDocument document = null;
FileOutputStream fos = null;
try {
document = new XWPFDocument(fis);
// 替换模板中的占位符
//在模板文件中,我们可以使用占位符来表示需要动态填充的内容,比如使用${placeholder}来表示占位符。我们需要遍历Word文档的所有段落和表格,找到包含占位符的位置,并将其替换为实际的内容。代码如下
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
String text = run.getText(0);
if (text != null && text.contains("${{成果名称}}")) {
text = text.replace("${{成果名称}}", "替换后的内容");
run.setText(text, 0);
}
}
}
// 表格处理方式
List<XWPFTable> tables = document.getTables();
for (XWPFTable table : tables) {
List<XWPFTableRow> rows = table.getRows();
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
List<XWPFParagraph> cellParagraphs = cell.getParagraphs();
for (XWPFParagraph cellParagraph : cellParagraphs) {
List<XWPFRun> runs = cellParagraph.getRuns();
for (XWPFRun run : runs) {
String text = run.getText(0);
if (text != null && text.contains("${{完成人姓名1}}")) {
text = text.replace("${{完成人姓名1}}", "替换后的内容");
run.setText(text, 0);
}
if (text != null && text.contains("${{成果名称}}")) {
text = text.replace("${{成果名称}}", "替换后的内容2222");
run.setText(text, 0);
}
}
}
}
}
}
// 导出word文档
// File outFile = new File("D:\\opt\\jwxt\\file\\uploadfile\\tt\\tt.docx");// 直接写磁盘
// fos = new FileOutputStream(outFile);
//
//// document.write(fos);//
String filePath = request.getSession().getServletContext().getRealPath("/");
String fileName = "tt.docx";
// response.setHeader("Content-Disposition", "attachment;fileName=" + stringToUnicode(fileName));
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
response.setContentType("multipart/form-data");
OutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
document.write(outputStream);
} catch (Exception e) {
log.error("获取word文档失败,原因是:" + e.getMessage());
} finally {
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
点击查看代码
// 导出占位符word
export function exportZwfWord (url,params,id,callback){
exportDataExcel(url,params,{
header:{ },responseType:"blob"
}).then(response=>{
if (response.status==200){
let fileName = response.headers["content-disposition"].split(";")[1].split("filename=")[1];
const aLink = document.createElement("a");
document.body.appendChild(aLink);
aLink.style.display = "none";
const objectUrl = window.URL.createObjectURL(new Blob([response.data], { type: 'application/docx; charset=utf-8' }));
aLink.href = objectUrl;
aLink.download = decodeURI(fileName);
aLink.click();
document.body.removeChild(aLink);
message.success('导出成功')
callback(response.data);
return;
}else{
if (response.message) {
message.error(response.message);
} else {
message.error("没有数据");
}
callback();
}
})
}
遇到问题:
1。Java使用POI技术导出Word文档,报错Package should contain a content type part [M1.13]
解决方案:
因为XWPFDocument只支持docx,所以需要将doc文件另存为 docx. 切记不能直接改后缀,否则不生效的。
2。问题2:response的Content-Disposition写文件名要与前端对应,否则,导出undefined.
效果: