欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實(shí)現(xiàn)markdown格式內(nèi)容轉(zhuǎn)換為word

 更新時(shí)間:2025年03月08日 14:28:55   作者:xiaomifeng1010  
這篇文章主要為大家簡(jiǎn)單介紹了如何利用Java實(shí)現(xiàn)markdown格式內(nèi)容轉(zhuǎn)換為word文檔,文中的示例代碼簡(jiǎn)潔易懂,有需要的小伙伴可以參考一下

前言

最近有個(gè)需求,就是需要在項(xiàng)目中,初始添加的信息后,將詳情頁(yè)面導(dǎo)出為word文檔,下載下來(lái)可以繼續(xù)編輯。一開(kāi)始考慮word的樣式,字體等問(wèn)題,使用開(kāi)源的Apache POI,在保存為word內(nèi)容時(shí)候,樣式基本上會(huì)丟失,導(dǎo)致導(dǎo)出后的文檔樣式和在頁(yè)面上看的不太一樣,會(huì)出現(xiàn)錯(cuò)位等情況,希望使用商業(yè)版的word處理工具,比如Aspose Words或者Spire.Doc for Java(Spire.Doc for Java 中文教程)非常專(zhuān)業(yè),功能非常強(qiáng)大。但是付費(fèi)商業(yè)方案被否了,后來(lái)推薦直接導(dǎo)出為PDF格式,這樣后端基本上也不用處理,導(dǎo)出PDF后,使用Adobe Acrobat在轉(zhuǎn)換成Word即可,最后給了一個(gè)方案就是頁(yè)面保存為markdown格式內(nèi)容到數(shù)據(jù)庫(kù),然后下載時(shí)候,后端將markdown轉(zhuǎn)換為word即可。

實(shí)現(xiàn)步驟

首先添加java處理的相關(guān)依賴(lài):

 <!-- excel工具 練習(xí)的項(xiàng)目自身的依賴(lài)-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>
        
          <!-- 新添加的依賴(lài)-->
         <!--  markdown格式轉(zhuǎn)換為html      -->
        <dependency>
            <groupId>org.commonmark</groupId>
            <artifactId>commonmark</artifactId>
            <version>0.21.0</version>
        </dependency>
 
<!--        poi-tl和poi-tl-plugin-markdown是處理markdown格式轉(zhuǎn)換為word格式,處理只處理markdown轉(zhuǎn)換為html,只需要commonnark依賴(lài)即可-->
        <dependency>
            <groupId>com.deepoove</groupId>
            <artifactId>poi-tl</artifactId>
            <version>1.10.1</version>
        </dependency>
 
        <dependency>
            <groupId>com.deepoove</groupId>
            <artifactId>poi-tl-plugin-markdown</artifactId>
            <version>1.0.3</version>
        </dependency>

編寫(xiě)工具類(lèi)

package com.xiaomifeng1010.common.utils;
 
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.style.*;
import com.deepoove.poi.plugin.markdown.MarkdownRenderData;
import com.deepoove.poi.plugin.markdown.MarkdownRenderPolicy;
import com.deepoove.poi.plugin.markdown.MarkdownStyle;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
import org.springframework.core.io.ClassPathResource;
 
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
 
/**
 * @author xiaomifeng1010
 * @version 1.0
 * @date: 2024-08-24 17:23
 * @Description
 */
@UtilityClass
@Slf4j
public class MarkdownUtil {
 
 
    /**
     * markdown轉(zhuǎn)html
     *
     * @param markdownContent
     * @return
     */
    public String markdownToHtml(String markdownContent) {
        Parser parser = Parser.builder().build();
        Node document = parser.parse(markdownContent);
        HtmlRenderer renderer = HtmlRenderer.builder().build();
        String htmlContent = renderer.render(document);
        log.info(htmlContent);
        return htmlContent;
    }
 
 
    /**
     * 將markdown格式內(nèi)容轉(zhuǎn)換為word并保存在本地
     *
     * @param markdownContent
     * @param outputFileName
     */
    public void toDoc(String markdownContent, String outputFileName) {
        log.info("markdownContent:{}", markdownContent);
        MarkdownRenderData code = new MarkdownRenderData();
        code.setMarkdown(markdownContent);
        MarkdownStyle style = MarkdownStyle.newStyle();
        style = setMarkdownStyle(style);
        code.setStyle(style);
//      markdown樣式處理與word模板中的標(biāo)簽{{md}}綁定
        Map<String, Object> data = new HashMap<>();
        data.put("md", code);
 
        Configure config = Configure.builder().bind("md", new MarkdownRenderPolicy()).build();
        try {
//            獲取classpath
            String path = MarkdownUtil.class.getClassLoader().getResource("").getPath();
            log.info("classpath:{}", path);
            //由于部署到linux上后,程序是從jar包中去讀取resources下的文件的,所以需要使用流的方式讀取,所以獲取流,而不是直接使用文件路徑
 
            // 所以可以這樣獲取 InputStream resourceAsStream = MarkdownUtil.class.getClassLoader().getResourceAsStream("");
            // 建議使用spring的工具類(lèi)來(lái)獲取,如下
            ClassPathResource resource = new ClassPathResource("markdown" + File.separator + "markdown_template.docx");
            InputStream resourceAsStream = resource.getInputStream();
            XWPFTemplate.compile(resourceAsStream, config)
                    .render(data)
                    .writeToFile(path + "out_markdown_" + outputFileName + ".docx");
        } catch (IOException e) {
            log.error("保存為word出錯(cuò)");
        }
 
    }
 
    /**
     * 將markdown轉(zhuǎn)換為word文檔并下載
     *
     * @param markdownContent
     * @param response
     * @param fileName
     */
    public void convertAndDownloadWordDocument(String markdownContent, HttpServletResponse response, String fileName) {
        log.info("markdownContent:{}", markdownContent);
        MarkdownRenderData code = new MarkdownRenderData();
        code.setMarkdown(markdownContent);
        MarkdownStyle style = MarkdownStyle.newStyle();
        style = setMarkdownStyle(style);
 
        code.setStyle(style);
//      markdown樣式處理與word模板中的標(biāo)簽{{md}}綁定
        Map<String, Object> data = new HashMap<>();
        data.put("md", code);
        Configure configure = Configure.builder().bind("md", new MarkdownRenderPolicy()).build();
 
        try {
            fileName=URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
            //由于部署到linux上后,程序是從jar包中去讀取resources下的文件的,所以需要使用流的方式讀取,所以獲取流,而不是直接使用文件路徑
 
            // 所以可以這樣獲取 InputStream resourceAsStream = MarkdownUtil.class.getClassLoader().getResourceAsStream("");
            // 建議使用spring的工具類(lèi)來(lái)獲取,如下
            ClassPathResource resource = new ClassPathResource("markdown" + File.separator + "markdown_template.docx");
            InputStream resourceAsStream = resource.getInputStream();
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8") + ".docx");
//            contentType不設(shè)置也是也可以的,可以正常解析到
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=utf-8");
            XWPFTemplate template = XWPFTemplate.compile(resourceAsStream, configure)
                    .render(data);
            template.writeAndClose(response.getOutputStream());
        } catch (IOException e) {
            log.error("下載word文檔失敗:{}", e.getMessage());
        }
    }
 
 
    /**
     * 設(shè)置轉(zhuǎn)換為word文檔時(shí)的基本樣式
     * @param style
     * @return
     */
    public MarkdownStyle setMarkdownStyle(MarkdownStyle style) {
//        一定設(shè)置為false,不然生成的word文檔中各元素前邊都會(huì)加上有層級(jí)效果的一串?dāng)?shù)字,
//        比如一級(jí)標(biāo)題 前邊出現(xiàn)1 二級(jí)標(biāo)題出現(xiàn)1.1 三級(jí)標(biāo)題出現(xiàn)1.1.1這樣的數(shù)字
        style.setShowHeaderNumber(false);
        // 修改默認(rèn)的表格樣式
        // table header style(表格頭部,通常為表格頂部第一行,用于設(shè)置列標(biāo)題)
        RowStyle headerStyle = new RowStyle();
        CellStyle cellStyle = new CellStyle();
//        設(shè)置表格頭部的背景色為灰色
        cellStyle.setBackgroundColor("cccccc");
        Style textStyle = new Style();
//        設(shè)置表格頭部的文字顏色為黑色
        textStyle.setColor("000000");
//        頭部文字加粗
        textStyle.setBold(true);
//        設(shè)置表格頭部文字大小為12
        textStyle.setFontSize(12);
//       設(shè)置表格頭部文字垂直居中
        cellStyle.setVertAlign(XWPFTableCell.XWPFVertAlign.CENTER);
 
        cellStyle.setDefaultParagraphStyle(ParagraphStyle.builder().withDefaultTextStyle(textStyle).build());
        headerStyle.setDefaultCellStyle(cellStyle);
        style.setTableHeaderStyle(headerStyle);
 
//        table border style(表格邊框樣式)
        BorderStyle borderStyle = new BorderStyle();
//        設(shè)置表格邊框顏色為黑色
        borderStyle.setColor("000000");
//        設(shè)置表格邊框?qū)挾葹?px
        borderStyle.setSize(3);
//        設(shè)置表格邊框樣式為實(shí)線(xiàn)
        borderStyle.setType(XWPFTable.XWPFBorderType.SINGLE);
        style.setTableBorderStyle(borderStyle);
 
//        設(shè)置普通的引用文本樣式
        ParagraphStyle quoteStyle = new ParagraphStyle();
//        設(shè)置段落樣式
        quoteStyle.setSpacingBeforeLines(0.5d);
        quoteStyle.setSpacingAfterLines(0.5d);
 
//        設(shè)置段落的文本樣式
        Style quoteTextStyle = new Style();
        quoteTextStyle.setColor("000000");
        quoteTextStyle.setFontSize(8);
        quoteTextStyle.setItalic(true);
        quoteStyle.setDefaultTextStyle(quoteTextStyle);
        style.setQuoteStyle(quoteStyle);
 
        return style;
    }
 
 
    public static void main(String[] args) {
        String markdownContent = "# 一級(jí)標(biāo)題\n" +
                "## 二級(jí)標(biāo)題\n" +
                "### 三級(jí)標(biāo)題\n" +
                "#### 四級(jí)標(biāo)題\n" +
                "##### 五級(jí)標(biāo)題\n" +
                "###### 六級(jí)標(biāo)題\n" +
                "## 段落\n" +
                "這是一段普通的段落。\n" +
                "## 列表\n" +
                "### 無(wú)序列表\n" +
                "- 項(xiàng)目1\n" +
                "- 項(xiàng)目2\n" +
                "- 項(xiàng)目3\n" +
                "### 有序列表\n" +
                "1. 項(xiàng)目1\n" +
                "2. 項(xiàng)目2\n" +
                "3. 項(xiàng)目3\n" +
                "## 鏈接\n" +
                "[百度](https://www.baidu.com)\n" +
                "## 圖片\n" +
                "![圖片描述](https://www.baidu.com/img/bd_logo1.png)\n" +
                "## 表格\n" +
                "| 表頭1 | 表頭2 | 表頭3 |\n" +
                "|-------|-------|-------|\n" +
                "| 單元格1 | 單元格2 | 單元格3 |\n" +
                "| 單元格4 | 單元格5 | 單元格6 |";
        toDoc(markdownContent, "test23");
 
 
    }
}

這個(gè)代碼是初步版本,導(dǎo)出的文檔直接保存在了本地,初步測(cè)試成功。如果運(yùn)行main方法測(cè)試報(bào)錯(cuò),比如這樣:

提示找不到xx方法,是因?yàn)樾绿砑拥膒oi-tl依賴(lài)的版本問(wèn)題,因?yàn)轫?xiàng)目是使用的ruoyi腳手架的版本比較古老,項(xiàng)目本身依賴(lài)的poi版本比較舊是4.X版本,所以將poi-tl版本降低一點(diǎn)就行了,比如使用1.10.1版本,然后再次運(yùn)行就成功了

   轉(zhuǎn)換markdown到word過(guò)程中,首先需要一個(gè)word模板,實(shí)際上還是用markdown內(nèi)容經(jīng)過(guò)markdown渲染器渲染后的內(nèi)容去填充word模版中的占位符{{md}}

word模版可以從poi-tl項(xiàng)目的官方github倉(cāng)庫(kù)下載:https://github.com/Sayi/poi-tl/tree/master/poi-tl-plugin-markdown/src/test/resources

將這個(gè)markdown文件夾放在本項(xiàng)目的resources目錄下就可以了

里邊有5個(gè)文件,其中4個(gè)md文件主要是為了測(cè)試使用的,word文件是用于渲染的模版

內(nèi)容是這樣的:

然后執(zhí)行剛才工具類(lèi)中main方法成功后,在項(xiàng)目target下就會(huì)生成一個(gè)新的渲染markdown內(nèi)容填充后的word文檔

內(nèi)容為這樣:

生成的效果還不錯(cuò)。

如果你直接用md文件測(cè)試,而不是使用一段md格式的字符串,測(cè)試方法可以參考官方的測(cè)試方法:

package com.deepoove.poi.plugin.markdown;
 
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
 
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
 
public class MarkdownTest {
 
    public static void testMarkdown(String name) throws Exception {
        MarkdownRenderData code = new MarkdownRenderData();
        byte[] bytes = Files.readAllBytes(Paths.get("src/test/resources/markdown/" + name + ".md"));
        String mkdn = new String(bytes);
        code.setMarkdown(mkdn);
 
        MarkdownStyle style = MarkdownStyle.newStyle();
        style.setShowHeaderNumber(true);
        code.setStyle(style);
 
        Map<String, Object> data = new HashMap<>();
        data.put("md", code);
 
        Configure config = Configure.builder().bind("md", new MarkdownRenderPolicy()).build();
        XWPFTemplate.compile("src/test/resources/markdown/markdown_template.docx", config)
                .render(data)
                .writeToFile("target/out_markdown_" + name + ".docx");
    }
 
    public static void main(String[] args) throws Exception {
        testMarkdown("api");
        testMarkdown("func");
        testMarkdown("README");
    }
 
}

實(shí)際項(xiàng)目中是需要web導(dǎo)出下載word文件的,所以在接口調(diào)用的時(shí)候,需要修改成輸出流的方式就可以了。具體使用方法可以參考官方中文文檔:Poi-tl Documentation

 不過(guò)今天訪(fǎng)問(wèn)不了了,網(wǎng)站掛掉了,昨天還是可以正常訪(fǎng)問(wèn)的

現(xiàn)在直接提示這個(gè),不知道什么原因,可能過(guò)幾天就可以正常訪(fǎng)問(wèn)了 ,還有就是模版文件中有個(gè)海豚的背景,項(xiàng)目中使用不想要這個(gè)背景,可以在word文檔中去掉

通過(guò)菜單欄【設(shè)計(jì)】->【水印】->【刪除水印】即可

以上就是Java實(shí)現(xiàn)markdown格式內(nèi)容轉(zhuǎn)換為word的詳細(xì)內(nèi)容,更多關(guān)于Java markdown轉(zhuǎn)word的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • maven導(dǎo)入本地jar包的三種方式

    maven導(dǎo)入本地jar包的三種方式

    本文主要介紹了maven導(dǎo)入本地jar包的三種方式,?文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-04-04
  • java中Integer包裝類(lèi)裝箱的一個(gè)細(xì)節(jié)詳解

    java中Integer包裝類(lèi)裝箱的一個(gè)細(xì)節(jié)詳解

    Java中的Integer是int的包裝類(lèi)型,下面這篇文章主要給大家介紹了關(guān)于java中Integer包裝類(lèi)裝箱的一個(gè)細(xì)節(jié)的相關(guān)資料,文中介紹的這個(gè)細(xì)節(jié)挺重要的,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起看看吧
    2018-07-07
  • Springmvc ResponseBody響應(yīng)json數(shù)據(jù)實(shí)現(xiàn)過(guò)程

    Springmvc ResponseBody響應(yīng)json數(shù)據(jù)實(shí)現(xiàn)過(guò)程

    這篇文章主要介紹了Springmvc ResponseBody響應(yīng)json數(shù)據(jù)實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Scala中的mkString的具體使用方法

    Scala中的mkString的具體使用方法

    這篇文章主要介紹了Scala中的mkString的具體方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-06-06
  • SpringBoot+kaptcha實(shí)現(xiàn)圖片驗(yàn)證碼功能詳解

    SpringBoot+kaptcha實(shí)現(xiàn)圖片驗(yàn)證碼功能詳解

    這篇文章主要為大家詳細(xì)介紹了SpringBoot如何結(jié)合kaptcha實(shí)現(xiàn)圖片驗(yàn)證碼功能,文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考一下
    2024-01-01
  • SpringBoot通過(guò)計(jì)劃任務(wù)發(fā)送郵件提醒的代碼詳解

    SpringBoot通過(guò)計(jì)劃任務(wù)發(fā)送郵件提醒的代碼詳解

    在實(shí)際線(xiàn)上項(xiàng)目中,有不斷接受到推送方發(fā)來(lái)的數(shù)據(jù)場(chǎng)景,而且是不間斷的發(fā)送,如果忽然間斷了,應(yīng)該是出問(wèn)題了,需要及時(shí)檢查原因,這種情況比較適合用計(jì)劃任務(wù)做檢查判斷,出問(wèn)題發(fā)郵件提醒,本文給大家介紹了SpringBoot通過(guò)計(jì)劃任務(wù)發(fā)送郵件提醒,需要的朋友可以參考下
    2024-11-11
  • java中如何對(duì)arrayList按數(shù)字大小逆序排序

    java中如何對(duì)arrayList按數(shù)字大小逆序排序

    這篇文章主要介紹了java中如何對(duì)arrayList按數(shù)字大小逆序排序問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • SpringBoot項(xiàng)目整合MybatisPlus并使用SQLite作為數(shù)據(jù)庫(kù)的過(guò)程

    SpringBoot項(xiàng)目整合MybatisPlus并使用SQLite作為數(shù)據(jù)庫(kù)的過(guò)程

    SQLite是一個(gè)緊湊的庫(kù),啟用所有功能后,庫(kù)大小可以小于 750KiB, 具體取決于目標(biāo)平臺(tái)和編譯器優(yōu)化設(shè)置, 內(nèi)存使用量和速度之間需要權(quán)衡,這篇文章主要介紹了SpringBoot項(xiàng)目整合MybatisPlus并使用SQLite作為數(shù)據(jù)庫(kù),需要的朋友可以參考下
    2024-07-07
  • java接口冪等性的實(shí)現(xiàn)方式

    java接口冪等性的實(shí)現(xiàn)方式

    本文介紹了在不同層面上實(shí)現(xiàn)Java接口冪等性的方法,包括使用冪等表、Nginx+Lua和Redis、以及SpringAOP,通過(guò)這些方法,可以確保接口在多次請(qǐng)求時(shí)只執(zhí)行一次,避免重復(fù)處理和數(shù)據(jù)不一致,每種方法都有其適用場(chǎng)景和優(yōu)勢(shì),通過(guò)實(shí)際測(cè)試驗(yàn)證了冪等性邏輯的有效性
    2025-01-01
  • SpringBoot項(xiàng)目@Async方法問(wèn)題解決方案

    SpringBoot項(xiàng)目@Async方法問(wèn)題解決方案

    這篇文章主要介紹了SpringBoot項(xiàng)目@Async方法問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04

最新評(píng)論