文档章节

Java 实现 markdown转Html

小灰灰Blog
 小灰灰Blog
发布于 2017/09/11 20:02
字数 1207
阅读 260
收藏 2
点赞 0
评论 0

背景

将markdown文档转换为html,主要是web应用中有些场景会用到,如博客系统,支持markdown语法的评论功能等

要自己去实现这个功能,并没有那么简单,当然面向GitHub编程,就简单很多了

设计

1. markdown 转 html

在github上相关的开源包还是比较多的,选择了一个之前看 Solo (一个开源的java博客系统)源码时,接触到的辅助包 flexmark

因为flexmark 工程比较庞大,我们这里只依赖其中的markdown转html的工具类,所以只需要添加下面的依赖即可

<!--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中查看,下面给出一个从文件中读取内容并转换的过程

// 从文件中读取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);

实现

上面给出了设计思路,主要是利用开源包进行转换,在此基础上进行封装,使得调用方式更加友好

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 属性

  • 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);
    }

}

测试

测试代码比较简单,下面三行即可

@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

个人博客:一灰的个人博客

公众号获取更多:

个人信息

© 著作权归作者所有

共有 人打赏支持
小灰灰Blog
粉丝 162
博文 161
码字总数 267290
作品 0
武汉
程序员
基于 Java 的代码注释 - XDoc-Java

XDoc, 是基于Java语言编写,提供将Java方法上的注释转成接口文档的工具.不同于sun doc生成的Java文档, XDoc只专注于对外接口层的文档转译, 基于原有的sun doc注解,加上扩展的一些,为使用者提...

风里的叶子
07/13
0
0
sharding-jdbc源码分析—准备工作

原文作者:阿飞Javaer 原文链接:https://www.jianshu.com/p/7831817c1da8 接下来对sharding-jdbc源码的分析基于tag为源码,根据sharding-jdbc Features深入学习sharding-jdbc的几个主要特性...

飞哥-Javaer
05/03
0
0
zrlog 1.10 发布,Java 构建的简约且好用的开源博客程序

ZrLog是使用Java开发的博客/CMS程序,具有简约,易用,组件化,内存占用低等特点。自带Markdown编辑器,让更多的精力放在写作上,而不是花费大量时间在学习程序的使用上。 v1.5以后版本可通过...

hibegin
05/08
0
0
Centos下安装类百度文库环境

使用php实现百度文库功能,网上搜索到的方案,实现doc转pdf,pdf转swf,然后显示出来。 这里简单的记录下,【doc转pdf,pdf转swf】两个功能的搭建流程。 doc转pdf 使用到下列程序(文件): Ap...

DragonFK
2013/02/20
0
1
如何以Java实现网页截图技术

今天看到某网友关于“如何以Java实现网页截图技术”的咨询帖,由于出现该咨询的地点非常不适合较长回复,故以博文形式回答。 事实上,如果您想以Java实现网页截图,也就是“输入一段网址,几...

Carl_
2015/03/03
0
7
[转]jsp编码 补充 关于JSP页面中的pageEncoding和contentType两种属性的区别

关于JSP页面中的pageEncoding和contentType两种属性的区别: pageEncoding是jsp文件本身的编码 contentType的charset是指服务器发送给客户端时的内容编码 JSP要经过两次的“编码”,第一阶段...

穿越星辰
2010/05/13
0
0
[转]jsp编码 补充 关于JSP页面中的pageEncoding和contentType两种属性的区别

关于JSP页面中的pageEncoding和contentType两种属性的区别: pageEncoding是jsp文件本身的编码 contentType的charset是指服务器发送给客户端时的内容编码 JSP要经过两次的“编码”,第一阶段...

inferrrrrr
2010/05/11
0
0
sublime text2的snippet设置

打开tools-new snippet.. <snippet> <content><![CDATA[ Hello, ${1:this} is a ${2:snippet}. ]]></content> <!-- Optional: Set a tabTrigger to define how to trigger the snippet --> <......

hhhhfengxing
2013/12/21
0
0
sharding-jdbc源码解析全集

本文转自“天河聊技术”微信公众号 sharding-jdbc源码解析之词法解析 sharding源码解析之api分析 sharding-jdbc源码解析之spring集成 sharding-jdbc源码解析之spring集成分片构造实现 shardi...

天河2018
05/03
0
0
10 个最受欢迎的 Java 开发的 CMS 系统

转于:http://www.oschina.net/news/32888/10-most-popular-java-based-cms CMS是Content Management System的缩写,意为"内容管理系统",它具有许多基于模板的优秀设计,可以加快网站开发的...

stamen
2015/08/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

expect(spawn) 自动化git提交和scp拷贝---centos(linux)

**在进行SCP文件拷贝中,往往需要进行用户密码的输入,即用户交互。若采用自动化脚本的方式进行,则可用以下方式: ** #!/usr/bin/expect #设置参数 set src [lindex $argv 0] set dest [lin...

helplove
刚刚
0
0
用Build来构建对象的写法

如果一个类的属性过多,用构造器来构建对象很难写,因此我们时用Build方式来构建对象。写法大致如下。 import java.io.Serializable;import java.util.Date;public class Log impleme...

算法之名
3分钟前
0
0
利用 acme.sh 获取网站证书并配置https访问

acme.sh 实现了 acme 协议, 可以从 letsencrypt 生成免费的证书.(https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E) 主要步骤: 安装 acme.sh 生成证书 copy 证书到 nginx/ap...

haoyuehong
16分钟前
2
0
微擎框架内如何根据media_id获取到微信图片的路径

微擎的框架内,图片选择后,获取的是那个字符串是media_id,相当于你这张图片在微信的图片服务器里面的id 要求是:获取https://mmbiz.qpic.cn/mmbiz_jpg/…… 微信图片的路径 而微信并没有根据m...

老bia同学
20分钟前
1
0
Spring boot中日期的json格式化

Model 在model层中,类的日期属性上面添加如下注解: @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss") 参考 Jackson Date格式化教程...

亚林瓜子
21分钟前
2
0
Eclipse:Failed to load the JNI shared library

1.问题背景: 由于我之前使用jdk1.9学习,当使用Luke的时候发现jdk版本过高,需要向下配置jdk,就向朋友拷了一个安装包。重新配置路径后,便开始报错。 2.问题描述: Failed to load the JNI...

tinder_boy
24分钟前
0
0
少儿学习编程课程是否真的适合七八岁的低龄儿童[图]

少儿学习编程课程是否真的适合七八岁的低龄儿童[图]: 天下熙熙皆为利来,天下攘攘皆为利往。 这几年来,乐高教育机构在国内如同雨后春笋般出现,当然关闭/转手的也很多。从教师角度来看,部...

原创小博客
29分钟前
1
0
ES12-词项查询

1.词项查询介绍 全文查询将在执行之前分析查询字符串,但词项级别查询将按照存储在倒排索引中的词项进行精确操作。这些查询通常用于数字,日期和枚举等结构化数据,而不是全文本字段。 或者,...

贾峰uk
37分钟前
2
0
http状态码与ajax的状态值

ajax状态值 1.1 200 & OK:状态请求成功

litCabbage
40分钟前
1
0
iOS动画效果合集、飞吧企鹅游戏、换肤方案、画板、文字效果等源码

iOS精选源码 动画知识运用及常见动画效果收集 3D卡片拖拽卡片叠加卡片 iFIERO - FLYING PENGUIN 飞吧企鹅SpriteKit游戏(源码) Swift封装的空数据提醒界面EmptyView 沙盒文件浏览与分享调试控...

sunnyaigd
44分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部