Java 實現 markdown轉Html

背景

將markdown文檔轉換爲html,主要是web應用中有些場景會用到,如博客系統,支持markdown語法的評論功能等css

要本身去實現這個功能,並無那麼簡單,固然面向GitHub編程,就簡單不少了html

設計

1. markdown 轉 html

在github上相關的開源包仍是比較多的,選擇了一個以前看 Solo (一個開源的java博客系統)源碼時,接觸到的輔助包 flexmarkjava

由於flexmark 工程比較龐大,咱們這裏只依賴其中的markdown轉html的工具類,因此只須要添加下面的依賴便可git

<!--markdown to html-->
<dependency>
	<groupId>com.vladsch.flexmark</groupId>
	<artifactId>flexmark</artifactId>
	<version>0.26.4</version>
</dependency>
<dependency>
	<groupId>com.vladsch.flexmark</groupId>
	<artifactId>flexmark-util</artifactId>
	<version>0.26.4</version>
</dependency>
<!--表格渲染插件-->
<dependency>
	<groupId>com.vladsch.flexmark</groupId>
	<artifactId>flexmark-ext-tables</artifactId>
	<version>0.26.4</version>
</dependency>

使用姿式也比較簡單,從demo中查看,下面給出一個從文件中讀取內容並轉換的過程github

// 從文件中讀取markdown內容
InputStream stream = this.getClass().getClassLoader().getResourceAsStream("test.md");
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "utf-8"));

List<String> list = reader.lines().collect(Collectors.toList());
String content = Joiner.on("\n").join(list);



// markdown to image
MutableDataSet options = new MutableDataSet();
options.setFrom(ParserEmulationProfile.MARKDOWN);
options.set(Parser.EXTENSIONS, Arrays.asList(new Extension[] { TablesExtension.create()}));
Parser parser = Parser.builder(options).build();
HtmlRenderer renderer = HtmlRenderer.builder(options).build();

Node document = parser.parse(content);
String html = renderer.render(document);

實現

上面給出了設計思路,主要是利用開源包進行轉換,在此基礎上進行封裝,使得調用方式更加友好web

0. 依賴

pom直接依賴便可編程

<!--markdown to html-->
<dependency>
    <groupId>com.vladsch.flexmark</groupId>
    <artifactId>flexmark</artifactId>
    <version>${flexmark.version}</version>
</dependency>
<dependency>
    <groupId>com.vladsch.flexmark</groupId>
    <artifactId>flexmark-util</artifactId>
    <version>${flexmark.version}</version>
</dependency>
<dependency>
    <groupId>com.vladsch.flexmark</groupId>
    <artifactId>flexmark-ext-tables</artifactId>
    <version>${flexmark.version}</version>
</dependency>
<!--markdown to html end-->

1. MarkdownEntity

這個entity類除了markdown轉換後的html內容以外,還增長了cssdivStyle 屬性markdown

  • css 屬性,主要是用於美化輸出html的展現樣式
  • divStyle 一樣也是爲了定義一些通用的屬性,會在html內容外層加一個<div>標籤,能夠在其中進行統一的寬高設置,字體....
@Data
public class MarkdownEntity {

    public static String TAG_WIDTH = "<style type=\"text/css\"> %s { width:85%%} </style>";

    // css 樣式
    private String css;

    // 最外網的div標籤, 能夠用來設置樣式,寬高,字體等
    private Map<String, String> divStyle = new ConcurrentHashMap<>();

    // 轉換後的html文檔
    private String html;

    public MarkdownEntity() {
    }

    public MarkdownEntity(String html) {
        this.html = html;
    }

    @Override
    public String toString() {
        return css + "\n<div " + parseDiv() + ">\n" + html + "\n</div>";
    }


    private String parseDiv() {
        StringBuilder builder = new StringBuilder();
        for (Map.Entry<String, String> entry : divStyle.entrySet()) {
            builder.append(entry.getKey()).append("=\"")
            .append(entry.getValue()).append("\" ");
        }
        return builder.toString();
    }


    public void addDivStyle(String attrKey, String value) {
        if (divStyle.containsKey(attrKey)) {
            divStyle.put(attrKey, divStyle.get(attrKey) + " " + value);
        } else {
            divStyle.put(attrKey, value);
        }
    }


    public void addWidthCss(String tag) {
        String wcss = String.format(TAG_WIDTH, tag);
        css += wcss;
    }
}

2. MarkDown2HtmlWrapper

操做封裝類網絡

  • 從git上找了一個簡單markdown.css樣式, 爲了不每次都去文件中讀,這裏定義一個靜態變量 MD_CSS
  • 爲了利用css樣式,須要給 MarkdownEntity 的 divStyle 新增一個 class: markdown-body 樣式
  • markdown to html 的主要邏輯在 parse 方法中,注意下爲了支持table,加載了對應的table插件
public class MarkDown2HtmlWrapper {

    private static String MD_CSS = null;

    static {
        try {
            MD_CSS = FileReadUtil.readAll("md/huimarkdown.css");
            MD_CSS = "<style type=\"text/css\">\n" + MD_CSS + "\n</style>\n";
        } catch (Exception e) {
            MD_CSS = "";
        }
    }


    /**
     * 將本地的markdown文件,轉爲html文檔輸出
     *
     * @param path 相對地址or絕對地址 ("/" 開頭)
     * @return
     * @throws IOException
     */
    public static MarkdownEntity ofFile(String path) throws IOException {
        return ofStream(FileReadUtil.getStreamByFileName(path));
    }


    /**
     * 將網絡的markdown文件,轉爲html文檔輸出
     *
     * @param url http開頭的url格式
     * @return
     * @throws IOException
     */
    public static MarkdownEntity ofUrl(String url) throws IOException {
        return ofStream(FileReadUtil.getStreamByFileName(url));
    }


    /**
     * 將流轉爲html文檔輸出
     *
     * @param stream
     * @return
     */
    public static MarkdownEntity ofStream(InputStream stream) {
        BufferedReader bufferedReader = new BufferedReader(
            new InputStreamReader(stream, Charset.forName("UTF-8")));
        List<String> lines = bufferedReader.lines().collect(Collectors.toList());
        String content = Joiner.on("\n").join(lines);
        return ofContent(content);
    }


    /**
     * 直接將markdown語義的文本轉爲html格式輸出
     *
     * @param content markdown語義文本
     * @return
     */
    public static MarkdownEntity ofContent(String content) {
        String html = parse(content);
        MarkdownEntity entity = new MarkdownEntity();
        entity.setCss(MD_CSS);
        entity.setHtml(html);
        entity.addDivStyle("class", "markdown-body ");
        return entity;
    }


    /**
     * markdown to image
     *
     * @param content markdown contents
     * @return parse html contents
     */
    public static String parse(String content) {
        MutableDataSet options = new MutableDataSet();
        options.setFrom(ParserEmulationProfile.MARKDOWN);

        // enable table parse!
        options.set(Parser.EXTENSIONS, Arrays.asList(TablesExtension.create()));


        Parser parser = Parser.builder(options).build();
        HtmlRenderer renderer = HtmlRenderer.builder(options).build();

        Node document = parser.parse(content);
        return renderer.render(document);
    }

}

測試

測試代碼比較簡單,下面三行便可app

@Test
public void markdown2html() throws IOException {
    String file = "md/tutorial.md";
    MarkdownEntity html = MarkDown2HtmlWrapper.ofFile(file);
    System.out.println(html.toString());
}

markdown 文件以下

Markdown cells support standard Markdown syntax as well as GitHub Flavored Markdown (GFM). Open the preview to see these rendered.

### Basics

# H1
## H2
### H3
#### H4
##### H5
###### H6

---

*italic*, **bold**, ~~Scratch this.~~

`inline code`

### Lists

1. First ordered list item
2. Another item
  * Unordered sub-list. 
1. Actual numbers don't matter, just that it's a number
  1. Ordered sub-list
4. And another item.

### Quote

> Peace cannot be kept by force; it can only be achieved by understanding.

### Links

[I'm an inline-style link](https://www.google.com)
http://example.com

You can also create a link to another note: (Note menu -> Copy Note Link -> Paste)
[01 - Getting Started](quiver-note-url/D2A1CC36-CC97-4701-A895-EFC98EF47026)

### Tables

| Tables        | Are           | Cool  |
| ------------- |:-------------:| -----:|
| col 3 is      | right-aligned | $1600 |
| col 2 is      | centered      |   $12 |
| zebra stripes | are neat      |    $1 |

### GFM Task Lists

- [ ] a task list item
- [ ] list syntax required
- [ ] normal **formatting**, @mentions, #1234 refs
- [ ] incomplete
- [x] completed

### Inline LaTeX

You can use inline LaTeX inside Markdown cells as well, for example, $x^2$.

測試示意圖

testCase

其餘

項目地址:https://github.com/liuyueyi/quick-media

我的博客:一灰的我的博客

公衆號獲取更多:

我的信息

相關文章
相關標籤/搜索