java实现自定义导出word并且存在数学公式(latex/MathML)

1 篇文章 0 订阅
1 篇文章 0 订阅

解决思路

  1. 使用Freemarker 模版技术,在word 中编辑域去替换,可以便捷的实现简单的word导出,但是如果有数学公式的情况,域替换就没办法识别数学公式,直接使用letax 渲染的html格式的文本,也没办法识别---------------------此方案pass
  2. 通过把latex数学公式生成为图片导出word----------------------此方案可以实现,但是公式为图片不支持编辑
  3. 把导出word的内容原样的输出成一个完整的html 页面,并且将用到数学公式的地方使用latex/MathML格式处理,然后将整个页面导出成word-------------------此方案可以完美解决前两个方案的问题

基于以上分析,对方案三的实现如下:

程序环境

  1. Word测试文档:.docx 2013
  2. Word jar包:free spire.doc.jar 5.2.0
  3. 代码编译环境:IntelliJ IDEA
  4. Jdk版本:1.8.0+

准备需要使用到的Jar

  1. 手动导入:需下载jar包,解压并且将lib文件夹下的jar文件导入程序,进入File>Project Structure 如图1
  2. 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>&#x2212;</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();
        }
    }
}
  • 导出结果

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值