Solo 导入 Markdown 文章

本贴最后更新于 2171 天前,其中的信息可能已经时过境迁

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

如果你之前使用过静态博客系统(比如 Hexo、Jekyll),Solo 可以很方便地将你已有的 Markdown 文件进行导入,并且在最大程度上保留以前的元信息,比如发布时间、标签、自定义链接等。

导入时机

因为导入操作不是必要且高频的操作,所以设计上为了保持简单,我们选择在启动时扫描固定路径 markdowns 文件夹,然后将该文件夹下所有 *.md 文件进行解析并作为文章导入。

文件夹路径获取:

final ServletContext servletContext = SoloServletListener.getServletContext();
final String markdownsPath = servletContext.getRealPath("markdowns");

导入主逻辑:

final Collection<File> mds = FileUtils.listFiles(new File(markdownsPath), new String[]{"md"}, true);
if (null == mds || mds.isEmpty()) {
    return;
}

for (final File md : mds) {
    final String fileName = md.getName();
    if (StringUtils.equalsIgnoreCase(fileName, "README.md")) {
        continue;
    }

    try {
        final String fileContent = FileUtils.readFileToString(md, "UTF-8");
        final JSONObject article = parseArticle(fileName, fileContent);
        article.put(Article.ARTICLE_AUTHOR_ID, adminId);

        final JSONObject request = new JSONObject();
        request.put(Article.ARTICLE, article);

        final String id = articleMgmtService.addArticle(request);
        FileUtils.moveFile(md, new File(md.getPath() + "." + id));
        LOGGER.info("Imported article [" + article.optString(Article.ARTICLE_TITLE) + "]");
        succCnt++;
    } catch (final Exception e) {
        LOGGER.log(Level.ERROR, "Import file [" + fileName + "] failed", e);

        failCnt++;
        failSet.add(fileName);
    }
}

导入结束后原 md 文件将被重命名为 .md.{时间毫秒} 这样的格式,如不需要,可将这类后缀的文件删除。

文件解析

每个 md 文件都会按照 Hexo/Jekyll 定义的头部进行解析,以确定标题、标签等:

  • Hexo 头
  • Jekyll 头
  • 支持头信息中使用 descriptionsummaryabstract 作为文章摘要,如果没有的话将自动截取正文部分
  • 如果没有定义头信息,或者解析失败,则以文件名作为标题、Note 作为标签、当前时间作为发布时间进行导入,这也是导入普通 md 文件的规则

Hexo/Jekyll 的文件头是使用 Yaml 格式的,我们使用 org.yaml.snakeyaml 库进行解析:

fileContent = StringUtils.trim(fileContent);
String frontMatter = StringUtils.substringBefore(fileContent, "---");
if (StringUtils.isBlank(frontMatter)) {
    fileContent = StringUtils.substringAfter(fileContent, "---");
    frontMatter = StringUtils.substringBefore(fileContent, "---");
}

final JSONObject ret = new JSONObject();
final Yaml yaml = new Yaml();
Map elems;
try {
    elems = (Map) yaml.load(frontMatter);
} catch (final Exception e) {
    // treat it as plain markdown
    ret.put(Article.ARTICLE_TITLE, StringUtils.substringBeforeLast(fileName, "."));
    ret.put(Article.ARTICLE_CONTENT, fileContent);
    ret.put(Article.ARTICLE_ABSTRACT, Article.getAbstract(fileContent));
    ret.put(Article.ARTICLE_TAGS_REF, DEFAULT_TAG);
    ret.put(Article.ARTICLE_IS_PUBLISHED, true);
    ret.put(Article.ARTICLE_COMMENTABLE, true);
    ret.put(Article.ARTICLE_VIEW_PWD, "");

    return ret;
}

容错处理

解析时难免会遇到一些“不按套路出牌”的内容,为了尽量兼容各种情况,我们得做一些容错处理:

  • 缺少标题则按文件名作为标题
  • 兼容各种日期格式:yyyy/MM/dd HH:mm:ssyyyy-MM-dd HH:mm:ssdd/MM/yyyy HH:mm:ss 等,解析失败则以当前时间作为文章创建时间
  • 抽取摘要:依次获取 descriptionsummaryabstract,如果都没有则按默认规则抽取
  • 解析标签:依次获取 tagscategorycategorieskeywordkeywords,如果都没有则默认添加 Note 作为标签

所以,理论上即使不是 Hexo/Jekyll 的 md 文件,只是普通 md 文件也是可以导入 Solo 的。

  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    1436 引用 • 10056 回帖 • 490 关注
  • 设计
    115 引用 • 797 回帖 • 1 关注
  • 文档
    56 引用 • 1289 回帖 • 2 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • Mr-YH

    有没有教程,这个代码看不懂

    1 回复
  • kuteng

    已开始我被 Solo 吸引了。不过进一步了解后,准备放弃 Solo。
    因为通过上传一个 Makedown 文件,发布或更新一篇博文是我的硬性需求。因为我懒。
    我不想切换到博客的编辑页面去写博客。我只希望通过 Typora 等工具,维护一个充满 Makedown 文件的文件夹。有新修改的时候就执行一个命令将相关文件上传到博客系统进行更新。(通过 Hexo 等格式,可以该博客是更新还是新增,博客 ID 等信息)。

    1 回复
  • 88250

    Solo 是以传统的博客系统形式存在,所以使用体验上确实不够简洁。我们正在构思下一款产品,它将会是一款笔记类应用,可以管理本地 Markdown 文件,并接入社区分享讨论,在用户私有数据和社区公有数据方面做出权衡,让用户可以放心安全地保存私有笔记,同时也能将想要公开分享讨论的博文对接到社区生态。

    链滴笔记,连接点滴

    有望今年年底前发布第一版,届时可以再关注一下,看是否能够满足你的需求。非常感谢你的反馈建议,我们会认真考虑的 ❤️

  • PeterChu 1 评论

    有个问题啊,

    如何将社区已有的自己的文章导入到 Solo 中。能否

    1. 数据 中只能拿到 json 格式的,如果能拿到 md 文件也行。
    2. 或者在 Solo 中做个配置导入社区文章。

    😂 个人感觉这还是个比较有价值的需求,假如 10 个人中有 3 个用户需要,那 1 万人中就有 3 千人要搞。

    wulian 奈何自己技术有点菜,不然我来搞

    该回帖因已过时而被折叠
    1 回复
    1 操作
    PeterChu 在 2020-05-23 22:19:38 折叠了该回帖
    wulian 想想可能还是算了,确实不是很重要,有时间了我再研究研究
    PeterChu
  • 88250 1 赞同

    预计下个月社区端会支持帖子导出为 Markdown 文件,感谢建议。

  • PeterChu

    😄 嗯嗯,D 执行力真牛啊,感谢。我提的意见有时角度不同,或者其他因素,或许考虑不周,希望酌情采纳即可。

请输入回帖内容 ...