解决思路
- 使用Freemarker 模版技术,在word 中编辑域去替换,可以便捷的实现简单的word导出,但是如果有数学公式的情况,域替换就没办法识别数学公式,直接使用letax 渲染的html格式的文本,也没办法识别---------------------此方案pass
- 通过把latex数学公式生成为图片导出word----------------------此方案可以实现,但是公式为图片不支持编辑
- 把导出word的内容原样的输出成一个完整的html 页面,并且将用到数学公式的地方使用latex/MathML格式处理,然后将整个页面导出成word-------------------此方案可以完美解决前两个方案的问题
基于以上分析,对方案三的实现如下:
程序环境
- Word测试文档:.docx 2013
- Word jar包:free spire.doc.jar 5.2.0
- 代码编译环境:IntelliJ IDEA
- Jdk版本:1.8.0+
准备需要使用到的Jar
- 手动导入:需下载jar包,解压并且将lib文件夹下的jar文件导入程序,进入File>Project Structure 如图1
- Maven导入:pom.xml配置,如下:
<repositories>
<repository>
<id>com.e-iceblue</id>
<url>http://repo.e-iceblue.cn/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.doc.free</artifactId>
<version>5.2.0</version>
</dependency>
</dependencies>
准备HTML页面
- 页面效果:
- HTML源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Document</title>
</head>
<body>
<h1 style="text-align:center">测试带公式的word导出</h1>
<table style="width: 80%" border="1" cellspacing="1">
<thead>
<tr>
<th rowspan="2">工程</th> <!-- rowspan代表单元格纵向合并 -->
<th colspan="2">信息</th> <!-- colspan代表单元格横向合并 -->
</tr>
<tr>
<th>名称</th>
<th>公式</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">公式</td>
<td style="text-align:center">机车</td>
<td>
<div style="display: flex;">
CRDβ<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> <msubsup> <mn>87</mn> <mrow> <mn>09</mn> </mrow> <mrow> <mo>−</mo> <mn>0192</mn> </mrow> </msubsup></math>
</div>
</td>
</tr>
<tr>
<td style="text-align:center">公式</td>
<td style="text-align:center">数学</td>
<td>
<div style="display: flex;">
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mfrac><mrow><mpadded height="8.6pt" depth="3pt" width="0"><mrow></mrow></mpadded><mstyle displaystyle="false" scriptlevel="0"><mrow><mn>1</mn></mrow></mstyle></mrow><mrow><mpadded height="8.6pt" depth="3pt" width="0"><mrow></mrow></mpadded><mstyle displaystyle="false" scriptlevel="0"><mrow><mi>a</mi><mo>+</mo><mfrac><mrow><mpadded height="8.6pt" depth="3pt" width="0"><mrow></mrow></mpadded><mstyle displaystyle="false" scriptlevel="0"><mrow><mn>7</mn></mrow></mstyle></mrow><mrow><mpadded height="8.6pt" depth="3pt" width="0"><mrow></mrow></mpadded><mstyle displaystyle="false" scriptlevel="0"><mrow><mi>b</mi><mo>+</mo><mfrac><mrow><mpadded height="8.6pt" depth="3pt" width="0"><mrow></mrow></mpadded><mstyle displaystyle="false" scriptlevel="0"><mrow><mn>2</mn></mrow></mstyle></mrow><mrow><mpadded height="8.6pt" depth="3pt" width="0"><mrow></mrow></mpadded><mstyle displaystyle="false" scriptlevel="0"><mrow><mn>9</mn></mrow></mstyle></mrow></mfrac></mrow></mstyle></mrow></mfrac></mrow></mstyle></mrow></mfrac><mo>=</mo><mi>c</mi></math>
</div>
</td>
</tr>
<tr>
<td style="text-align:center">公式</td>
<td style="text-align:center">数学</td>
<td>
<div style="display: flex;">
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mfrac><mn>8</mn><mrow><mn>19</mn><msub><mi>log</mi><mrow><mn>87</mn></mrow></msub><mo data-mjx-texclass="NONE"></mo><mrow><mn>1</mn></mrow></mrow></mfrac><munder><mo data-mjx-texclass="OP" movablelimits="true">lim</mo><mrow><mi>x</mi><mo accent="false" stretchy="false">→</mo><mi mathvariant="normal">∞</mi></mrow></munder><msup><mi>tan</mi><mrow><mo>−</mo><mn>1</mn></mrow></msup><mo data-mjx-texclass="NONE"></mo><msup><mi>tan</mi><mrow><mo>−</mo><mn>1</mn></mrow></msup></math>
</div>
</td>
</tr>
</tbody>
</table>
</body>
</html>
JAVA编码实现
- html转word并将生成的文件保存到临时目录
/**
* 基于spire实现html转word
* html为字符串
* @param htmlFilePath html文件地址
* @param wordFileName word文件名称
* @return 生成的word临时文件
*/
public Path htmlToWord(String htmlFilePath, String wordFileName) {
// 创建Document对象
Document doc = new Document();
try {
// 加载HTML文件,设置XHTMLValidationType为None以保留原始样式和结构
doc.loadFromFile(htmlFilePath, FileFormat.Html, XHTMLValidationType.None);
//即上传文件路径path为:temp/***
Path tempFile = Files.createTempFile(wordFileName, SUFFIX);
// 保存为Word格式到指定路径
doc.saveToFile(tempFile.toAbsolutePath().toString(), FileFormat.Docx_2013);
log.info("HTML file successfully converted to Word: {}", tempFile.toAbsolutePath().toString());
return tempFile;
} catch (Exception e) {
log.error("Failed to convert HTML to Word: {}", e.getMessage());
e.printStackTrace();
} finally {
// 清理资源
doc.dispose();
}
return null;
}
- 基于文件流html转word并将生成的文件到指定目录
/**
* 基于spire实现html转word
* html文件流处理
* @param html html文件流
* @param wordFileUrl word文件地址
*/
public void htmlToWordStream(InputStream html, String wordFileUrl) {
// 创建Document对象
Document doc = new Document();
try {
// 加载HTML文件,设置XHTMLValidationType为None以保留原始样式和结构
doc.loadFromStream(html, FileFormat.Html, XHTMLValidationType.None);
// 保存为Word格式到指定路径
doc.saveToFile(wordFileUrl, FileFormat.Docx_2013);
log.info("HTML file successfully converted to Word: {}", wordFileUrl);
} catch (Exception e) {
log.error("Failed to convert HTML to Word: {}", e.getMessage());
e.printStackTrace();
} finally {
// 清理资源
doc.dispose();
}
}
- 删除临时文件
/**
* 删除临时文件
* @param path
*/
public void deleteTempFile(Path path) {
try {
Files.delete(path);
log.info("delete temp-file successfully url: {}", path.toAbsolutePath().toString());
} catch (Exception e) {
log.error("Failed delete temp-file error: {}", e.getMessage());
e.printStackTrace();
}
}
- 下载文件
/**
* @ClassName: Spire导出
* @Description: SpireWordController
* @author: gujing
* @date: 2024/4/23 13:43
*/
@Slf4j
@Api(tags="Spire导出")
@RestController
@RequestMapping("/aps_step/export")
public class SpireWordController {
private final FreedomWordUtil freedomWordUtil;
public SpireWordController(FreedomWordUtil freedomWordUtil) {
this.freedomWordUtil = freedomWordUtil;
}
@AutoLog(value = "将HTML导出成WORD")
@ApiOperation(value="将HTML导出成WORD", notes="将HTML导出成WORD")
@GetMapping("/html-to-word")
public ResponseEntity<FileSystemResource> downloadConvertedWord(@RequestParam("html") String htmlContent) throws IOException {
String htmlFilePath = "E:/path/to/your/demo.html";
String wordOutputPath = "output";
Path tempFile = freedomWordUtil.htmlToWord(htmlFilePath, wordOutputPath);
if (tempFile != null && Files.exists(tempFile)) {
String fileName = tempFile.getFileName().toString();
HttpHeaders headers = new HttpHeaders();
//根据文件扩展名设置更精确的MIME类型
headers.setContentType(MediaType.valueOf("application/vnd.openxmlformats-officedocument.wordprocessingml.document"));
headers.setContentDispositionFormData("attachment", fileName);
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
return ResponseEntity.status(HttpStatus.OK)
.headers(headers)
.body(new FileSystemResource(tempFile));
} else {
return ResponseEntity.notFound().build();
}
}
}
- 导出结果