Java处理markdown格式内容转换为word文档

随笔4个月前发布 一叶
49 0 0

        最近有个需求,就是需要在项目中,初始添加的信息后,将详情页面导出为word文档,下载下来可以继续编辑。一开始考虑word的样式,字体等问题,使用开源的Apache POI,在保存为word内容时候,样式基本上会丢失,导致导出后的文档样式和在页面上看的不太一样,会出现错位等情况,希望使用商业版的word处理工具,比如Aspose Words或者Spire.Doc for Java(Spire.Doc for Java 中文教程)非常专业,功能非常强大。但是付费商业方案被否了,后来推荐直接导出为PDF格式,这样后端基本上也不用处理,导出PDF后,使用Adobe Acrobat在转换成Word即可,最后给了一个方案就是页面保存为markdown格式内容到数据库,然后下载时候,后端将markdown转换为word即可。

      首先添加java处理的相关依赖:

  1. <!-- excel工具 ruoyi项目自身的依赖-->

  2. <dependency>

  3. <groupId>org.apache.poi</groupId>

  4. <artifactId>poi-ooxml</artifactId>

  5. <version>4.1.2</version>

  6. </dependency>

  7. <!-- 新添加的依赖-->

  8. <!-- markdown格式转换为html -->

  9. <dependency>

  10. <groupId>org.commonmark</groupId>

  11. <artifactId>commonmark</artifactId>

  12. <version>0.21.0</version>

  13. </dependency>

  14. <!-- poi-tl和poi-tl-plugin-markdown是处理markdown格式转换为word格式,处理只处理markdown转换为html,只需要commonnark依赖即可-->

  15. <dependency>

  16. <groupId>com.deepoove</groupId>

  17. <artifactId>poi-tl</artifactId>

  18. <version>1.10.1</version>

  19. </dependency>

  20. <dependency>

  21. <groupId>com.deepoove</groupId>

  22. <artifactId>poi-tl-plugin-markdown</artifactId>

  23. <version>1.0.3</version>

  24. </dependency>

编写工具类

  1. package com.ruoyi.common.utils;

  2. import com.deepoove.poi.XWPFTemplate;

  3. import com.deepoove.poi.config.Configure;

  4. import com.deepoove.poi.plugin.markdown.MarkdownRenderData;

  5. import com.deepoove.poi.plugin.markdown.MarkdownRenderPolicy;

  6. import com.deepoove.poi.plugin.markdown.MarkdownStyle;

  7. import lombok.experimental.UtilityClass;

  8. import lombok.extern.slf4j.Slf4j;

  9. import org.commonmark.node.Node;

  10. import org.commonmark.parser.Parser;

  11. import org.commonmark.renderer.html.HtmlRenderer;

  12. import javax.servlet.http.HttpServletResponse;

  13. import java.io.IOException;

  14. import java.net.URLEncoder;

  15. import java.util.HashMap;

  16. import java.util.Map;

  17. /**

  18. * @author xiaomifeng1010

  19. * @version 1.0

  20. * @date: 2024-08-24 17:23

  21. * @Description

  22. */

  23. @UtilityClass

  24. @Slf4j

  25. public class MarkdownUtil {

  26. /**

  27. * markdown转html

  28. * @param markdownContent

  29. * @return

  30. */

  31. public String markdownToHtml(String markdownContent){

  32. Parser parser = Parser.builder().build();

  33. Node document = parser.parse(markdownContent);

  34. HtmlRenderer renderer = HtmlRenderer.builder().build();

  35. String htmlContent = renderer.render(document);

  36. log.info(htmlContent);

  37. return htmlContent;

  38. }

  39. /**

  40. * 将markdown格式内容转换为word并保存在本地

  41. * @param markdownContent

  42. * @param outputFileName

  43. */

  44. public void toDoc(String markdownContent,String outputFileName){

  45. log.info("markdownContent:{}",markdownContent);

  46. MarkdownRenderData code = new MarkdownRenderData();

  47. code.setMarkdown(markdownContent);

  48. MarkdownStyle style = MarkdownStyle.newStyle();

  49. style.setShowHeaderNumber(true);

  50. code.setStyle(style);

  51. // markdown样式处理与word模板中的标签{{md}}绑定

  52. Map<String, Object> data = new HashMap<>();

  53. data.put("md", code);

  54. Configure config = Configure.builder().bind("md", new MarkdownRenderPolicy()).build();

  55. try {

  56. //获取classpath

  57. String path = MarkdownUtil.class.getClassLoader().getResource("").getPath();

  58. log.info("classpath:{}", path);

  59. XWPFTemplate.compile(path + "markdown" + File.separator + "markdown_template.docx", config)

  60. .render(data)

  61. .writeToFile(path+"out_markdown_" + outputFileName + ".docx");

  62. } catch (IOException e) {

  63. log.error("保存为word出错");

  64. }

  65. }

  66. /**

  67. * 将markdown转换为word文档并下载

  68. * @param markdownContent

  69. * @param response

  70. * @param fileName

  71. */

  72. public void convertAndDownloadWordDocument(String markdownContent, HttpServletResponse response,String fileName) {

  73. log.info("markdownContent:{}",markdownContent);

  74. MarkdownRenderData code = new MarkdownRenderData();

  75. code.setMarkdown(markdownContent);

  76. MarkdownStyle style = MarkdownStyle.newStyle();

  77. style.setShowHeaderNumber(true);

  78. code.setStyle(style);

  79. // markdown样式处理与word模板中的标签{{md}}绑定

  80. Map<String, Object> data = new HashMap<>();

  81. data.put("md", code);

  82. Configure config = Configure.builder().bind("md", new MarkdownRenderPolicy()).build();

  83. try {

  84. //获取classpath

  85. String path = MarkdownUtil.class.getClassLoader().getResource("").getPath();

  86. log.info("classpath:{}", path);

  87. XWPFTemplate template = XWPFTemplate.compile(path + "markdown" + File.separator + "markdown_template.docx", config)

  88. .render(data);

  89. template.writeAndClose(response.getOutputStream());

  90. response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")+".docx");

  91. response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=utf-8");

  92. } catch (IOException e) {

  93. log.error("下载word文档失败:{}", e.getMessage());

  94. }

  95. }

  96. public static void main(String[] args) {

  97. String markdownContent = "# 一级标题 " +

  98. "## 二级标题 " +

  99. "### 三级标题 " +

  100. "#### 四级标题 " +

  101. "##### 五级标题 " +

  102. "###### 六级标题 " +

  103. "## 段落 " +

  104. "这是一段普通的段落。 " +

  105. "## 列表 " +

  106. "### 无序列表 " +

  107. "- 项目1 " +

  108. "- 项目2 " +

  109. "- 项目3 " +

  110. "### 有序列表 " +

  111. "1. 项目1 " +

  112. "2. 项目2 " +

  113. "3. 项目3 " +

  114. "## 链接 " +

  115. "[百度](https://www.baidu.com) " +

  116. "## 图片 " +

  117. "![图片描述](https://www.baidu.com/img/bd_logo1.png) " +

  118. "## 表格 " +

  119. "| 表头1 | 表头2 | 表头3 | " +

  120. "|-------|-------|-------| " +

  121. "| 单元格1 | 单元格2 | 单元格3 | " +

  122. "| 单元格4 | 单元格5 | 单元格6 |";

  123. toDoc(markdownContent, "test23");

  124. }

  125. }

这个代码是初步版本,导出的文档直接保存在了本地,初步测试成功。如果运行main方法测试报错,比如这样:

 Java处理markdown格式内容转换为word文档

   提示找不到xx方法,是因为新添加的poi-tl依赖的版本问题,因为项目是使用的ruoyi脚手架的版本比较古老,项目本身依赖的poi版本比较旧是4.X版本,所以将poi-tl版本降低一点就行了,比如使用1.10.1版本,然后再次运行就成功了

Java处理markdown格式内容转换为word文档   

转换markdown到word过程中,首先需要一个word模板,实际上还是用markdown内容经过markdown渲染器渲染后的内容去填充word模版中的占位符{{md}}

word模版可以从poi-tl项目的官方github仓库下载:
https://github.com/Sayi/poi-tl/tree/master/poi-tl-plugin-markdown/src/test/resources

Java处理markdown格式内容转换为word文档

 将这个markdown文件夹放在本项目的resources目录下就可以了

Java处理markdown格式内容转换为word文档

里边有5个文件,其中4个md文件主要是为了测试使用的,word文件是用于渲染的模版

内容是这样的:

Java处理markdown格式内容转换为word文档

然后执行刚才工具类中main方法成功后,在项目target下就会生成一个新的渲染markdown内容填充后的word文档

Java处理markdown格式内容转换为word文档 

内容为这样:

Java处理markdown格式内容转换为word文档

生成的效果还不错。

如果你直接用md文件测试,而不是使用一段md格式的字符串,测试方法可以参考官方的测试方法:

 Java处理markdown格式内容转换为word文档

  1. package com.deepoove.poi.plugin.markdown;

  2. import java.nio.file.Files;

  3. import java.nio.file.Paths;

  4. import java.util.HashMap;

  5. import java.util.Map;

  6. import com.deepoove.poi.XWPFTemplate;

  7. import com.deepoove.poi.config.Configure;

  8. public class MarkdownTest {

  9. public static void testMarkdown(String name) throws Exception {

  10. MarkdownRenderData code = new MarkdownRenderData();

  11. byte[] bytes = Files.readAllBytes(Paths.get("src/test/resources/markdown/" + name + ".md"));

  12. String mkdn = new String(bytes);

  13. code.setMarkdown(mkdn);

  14. MarkdownStyle style = MarkdownStyle.newStyle();

  15. style.setShowHeaderNumber(true);

  16. code.setStyle(style);

  17. Map<String, Object> data = new HashMap<>();

  18. data.put("md", code);

  19. Configure config = Configure.builder().bind("md", new MarkdownRenderPolicy()).build();

  20. XWPFTemplate.compile("src/test/resources/markdown/markdown_template.docx", config)

  21. .render(data)

  22. .writeToFile("target/out_markdown_" + name + ".docx");

  23. }

  24. public static void main(String[] args) throws Exception {

  25. testMarkdown("api");

  26. testMarkdown("func");

  27. testMarkdown("README");

  28. }

  29. }

 实际项目中是需要web导出下载word文件的,所以在接口调用的时候,需要修改成输出流的方式就可以了。具体使用方法可以参考官方中文文档:Poi-tl Documentation

 不过今天访问不了了,网站挂掉了,昨天还是可以正常访问的

Java处理markdown格式内容转换为word文档

现在直接提示这个,不知道什么原因,可能过几天就可以正常访问了 

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...