"本文是[链接]的一个章节,该系列文章将介绍 [链接] 这款 Java 博客系统是如何从无到有的,希望大家能通过它对 Solo 从设计到实现有个直观地了解、能为想参与贡献的人介绍清楚项目,也希望能为给重复发明重新定义博客系统的人做个参考 Markdown 渲染 Markdown 渲染指的是将 Markdown 文本转换成 .."

Solo Markdown 渲染

本贴最后更新于 183 天前,其中的信息可能已经斗转星移

本文是《Solo 从设计到实现》的一个章节,该系列文章将介绍 Solo 这款 Java 博客系统是如何从无到有的,希望大家能通过它对 Solo 从设计到实现有个直观地了解、能为想参与贡献的人介绍清楚项目,也希望能为给重复发明重新定义博客系统的人做个参考 ❤️

Markdown 渲染

Markdown 渲染指的是将 Markdown 文本转换成 HTML 的过程。

引擎选择

Solo 默认是通过 flexmark-java 进行 Markdown 渲染的。如果启用了独立进程 markdown-http 则优先使用 markdown-http 渲染。

如果有可能的话,建议使用 markdown-http。因为从我们目前看到的渲染效果以及容错情况上看,markdown-http 是要比 flexmark 好一些的。使用独立渲染服务后,如果出现渲染异常,则会使用内置的 flexmark 进行兜底。

if (MARKDOWN_HTTP_AVAILABLE) {
    try {
        html = toHtmlByMarkdownHTTP(markdownText);
    } catch (final Exception e) {
        LOGGER.log(Level.WARN, "Failed to use [markdown-http] for markdown [md=" + StringUtils.substring(markdownText, 0, 256) + "]: " + e.getMessage());
        com.vladsch.flexmark.ast.Node document = PARSER.parse(markdownText);
        html = RENDERER.render(document);
    }
} else {
    com.vladsch.flexmark.ast.Node document = PARSER.parse(markdownText);
    html = RENDERER.render(document);
}

超时控制

Solo 的 Markdown 渲染是在一个新建线程中完成的,获取处理结果带超时控制(默认 10s)。这样做是为了防止一些无法预期的问题,比如引擎缺陷或是文本怪异导致渲染太耗时,从而耗尽服务线程。

站外链接处理

Markdown 渲染后得到的 HTML 还会通过 jsoup 解析一次,将其中的 a 标签获取出来,如果发现是站外链接,就将其 target 设置为 _blank,点击时以新页签方式打开。

final Document doc = Jsoup.parse(html);
doc.select("a").forEach(a -> {
    final String src = a.attr("href");
    if (!StringUtils.startsWithIgnoreCase(src, Latkes.getServePath())) {
        a.attr("target", "_blank");
    }
});

结果缓存

每次 Markdown 渲染后的最终 HTML 都会放入缓存,下次进行渲染时先从缓存中获取。缓存键是将原 Markdown 文本进行 MD5 哈希得到的,虽然存在一定碰撞的可能,但是目前的结果来看,这个可能性是非常低的。


回到全文目录:《Solo 从设计到实现》

  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。

    Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!
    具体细节请浏览 B3log 构思

    655 引用 • 4983 回帖 • 710 关注
  • 设计
    85 引用 • 528 回帖 • 1 关注
  • 文档
    51 引用 • 926 回帖 • 1 关注
17 回帖   
请输入回帖内容...
  • linker  

    markd 没有跑起来,还是不要搞那么多外部依赖比较好。

    1 回复
  • 88250      

    等有机会我会写个 Markdown 引擎,还有前端编辑器也想单独提出来开源。减少依赖,同时也可以丰富 B3log 开源项目,让更多的人参与进来完善。

    1 回复
  • linker        

    自己写一个 markdown 引擎啊,感觉很难啊。

  • zwxbest  

    希望后面可以支持更多图。

    1 回复
  • 88250      

    更多图?

    1 回复
  • zwxbest        

    类图,ER 图,时序图之类的,目前我用的是 plantuml。

  • lai-bluejay  

    solo 的 markdown 支持引入 html 或者 js 吗?
    有部分博客,尤其是前端,数据可视化,使用一些 css 或者 js 会方便呢; 就象 jekyll 里面,支持 includes,https://jekyllrb.com/docs/includes/

    我在社区里没有看到类似的帮助文档

    类似这个页面,如果直接复制 html 的话,渲染不成功呢。
    https://www.jithub.cn/articles/2019/04/18/1555561028799.html

    1 回复
  • 88250      

    贴代码的话用 Markdown 语法,如果直接展示效果的话可以使用 HTML 标签和 JS 的,没有做过滤。

    1 回复
  • lai-bluejay  

    抱歉,刚刚把之前的添加了实际页面
    https://www.jithub.cn/articles/2019/04/18/1555561028799.html

    本来期望是如下页面的
    https://www.jithub.cn/fileserver/activation_functions_d3.html

  • lai-bluejay        

    实际显示中,select 没有生效

    1 回复
  • 88250      

    select 时 F12 console 中有报错,看上去是 js 加载有问题。

    1 回复
  • lai-bluejay 1 评论        

    可能还是渲染的问题。
    我在可视化的内容里面用了 d3。

    给你看一下报错的对比:

    1. 最终期望的结果:https://www.jithub.cn/fileserver/activation_function_all_in_one.html
    2. 实际的结果:https://www.jithub.cn/articles/2019/04/18/1555558277373.html
    3. 我把中间的 html 的元素,包括 <style> <scripts> 都复制过来了,https://www.jithub.cn/fileserver/test2.html 右侧公式显示还是有问题
    1 回复
    @Vanessa 帮忙看看
    88250 1 赞同
  • Vanessa        

    现在好像是挪走了,有没有什么报错之类的。

    1 回复
  • lai-bluejay        

    原来影响内容展示,我放新的页面了,抱歉。
    在这儿:https://www.jithub.cn/articles/2019/04/18/1555582980606.html
    但实际单独移出来,还是能显示部份元素的:https://www.jithub.cn/fileserver/test2.html

    1 回复
  • iTanken  

    image.png

    启用 markdown-http 后访问某篇文章直接就崩了,返回 502,但再访问其他页面都是正常的:
    image.png

  • iTanken 1 评论  

    markdown-http 关闭后再访问页面是正常的,好像是因为文章和代码块中包含 Emoji 表情

    好吧好像又不是 markdown-http 的原因,不启用也会报这个错
    iTanken
  • Vanessa        

    看了下,两个页面的代码不一样。
    无法显示的 HTML 中 I 为大写,可以部分显示中的是小写,JavaScript 是区分大小写的。

      for (var i = -3; i <= 3; i = i + 0.001) {
        lineData.push({
          x: I,
          y: i >= 0
        });
        lineData_deriv.push({
          x: I,
          y: 0
        });
      }
    
请输入回帖内容 ...