关于springboot:SpringBoot集成markdown实现文档管理

37次阅读

共计 3652 个字符,预计需要花费 10 分钟才能阅读完成。

背景

最近在做一个部门外部简略的知识库零碎,便于新人入职理解与一些常见问题的解答,知识库的模式是以文档为主,为了疾速实现文档性能,决定采纳 markdown 模式录入,生成本地文件后以 html 形式展示,档次清晰便于查看

表结构设计

文档信息表

DROP TABLE IF EXISTS `knowledge_documentinfo`;
CREATE TABLE `knowledge_documentinfo` (`ID` int(11) NOT NULL AUTO_INCREMENT,
  `UnitGuid` varchar(50) DEFAULT NULL,
  `AddDate` datetime DEFAULT NULL,
  `DocName` varchar(50) DEFAULT NULL,
  `DocType` int(11) DEFAULT NULL,
  `DocRemark` varchar(500) DEFAULT NULL,
  `DocTag` varchar(100) DEFAULT NULL,
  `DocClass` int(11) DEFAULT NULL,
  `GroupGuid` varchar(50) DEFAULT NULL,
  `SortNum` int(11) DEFAULT NULL,
  KEY `ID` (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4;

文档内容表

DROP TABLE IF EXISTS `knowledge_documentcontentinfo`;
CREATE TABLE `knowledge_documentcontentinfo` (`ID` int(11) NOT NULL AUTO_INCREMENT,
  `UnitGuid` varchar(50) DEFAULT NULL,
  `DocGuid` varchar(50) DEFAULT NULL,
  `DocClass` int(11) DEFAULT NULL,
  `DocContent` longtext,
  KEY `ID` (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4;

前端集成

前端为了 markdown 编辑操作便捷,集成了 toastui-edit 编辑器,具备所见即所得模式,和 typora 一样的成果。因为咱们前端是本人开发,基于 vue+html 本地化形式开发,就简略封装了控件应用,同时须要援用 zh-cn.js 汉化,指定 initialEditType 模式为 wysiwyg

template

<div v-if="!readonly" id="markdownedit"></div>
<div v-else id="markdownedit_viewer">  </div>

index.js

var mdeditortemplatepath = GetRootPath() + 'component/commonmdeditor/template.html';
Vue.component('common-markdowneditor', function(resolve, reject) {$.get(mdeditortemplatepath).then(function(res) {
        resolve({
            template: res,
            model: {
                prop: 'value', // 要存在于 props
                event: 'change' // 当组件的值产生扭转时要 emit 的事件名
            },
            props: {value: {},
                height: {default: '300px'},
                readonly: {default: false}
            },

            data() {
                return {editorID: getNewGuid(),
                    editorImageStoreGroupType: "edtior",
                    editContent: this.value,
                    editorOption: {},
                    editorEntity: null,
                    editorViewEntity: null
                }
            },
            watch: {
                // 组件输出同步到页面绑定的变量
                editContent: function(newVal, oldVal) {this.$emit('change', newVal)
                },
                // 页面变量同步到组件显示
                value: function(newVal, oldVal) {
                    // 从页面向组件更新时
                    if (this.editContent != newVal) {
                        this.editContent = newVal;
                        if (this.editorEntity != null) {this.editorEntity.setMarkdown(newVal, false)
                        }
                        if (this.editorViewEntity != null) {this.editorViewEntity.setMarkdown(newVal, false)
                        }

                    }
                },
            },
            created() {var page = this;},
            mounted() {
                var page = this;
                this.$nextTick(function() {if (!page.readonly) {
                        page.editorEntity = new toastui.Editor({el: document.querySelector('#markdownedit'),
                            height: this.height,
                            initialValue: '',
                            initialEditType: 'wysiwyg',
                            hideModeSwitch: true,
                            language: "zh-CN",
                            events: {change: function() {page.editContent = page.editorEntity.getMarkdown();
                                }
                            }
                        })
                        page.editorEntity.setMarkdown(page.editContent, true)
                    } else {
                        page.editorViewEntity =  toastui.Editor.factory({el: document.querySelector('#markdownedit_viewer'),
                            viewer: true,
                            initialValue: page.editContent
                          });
                    }

                });


            },
            methods: {},})
    });
});

理论应用

 <common-markdowneditor v-model="form.docContent" ></common-markdowneditor>

后端集成

在把 markdonw 的内容保留到数据库后,同时同步生成本地 markdown 文件,为后续 html 展现做筹备

    public void creatMarkdownFile(DocumentContentInfoDO entity) {if (entity.getDocClass() == DocEnum.DocClass.Markdown.get_value()) {
            try {
                // 生成 markdown 文件
                String dicPath = "tempfiles/markdown/";
                String filePath = dicPath + entity.getDocGuid() + ".md";
                File dicInfo = new File(dicPath);
                if (!dicInfo.exists()) {dicInfo.mkdirs();
                }
                File file = new File(filePath);
                if (file.exists()) {file.delete();
                }
                file.createNewFile();
                BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(filePath)),"utf-8"));
                out.write(entity.getDocContent());
                out.close();} catch (Exception e) {e.printStackTrace();
            }

        }
    }

文档显示

前端显示集成了 docsify@4.js,通过动静的指定 homepage 主页 markdown 文件地址达到一个 index.html 页面依据文档标识显示不同内容的成果

<script>
    var showDocUrl = apiFrameUrl + "/foundation/documentinfo/getMarkdownUrl";
    var docTag = getUrlParam("docTag")
    $(function() {
        var data = {docTag: docTag,};
        JsonAjax_Sync(JSON.stringify(data), showDocUrl, function(result, status) {var mdFileUrl = GetRootPath() + result.data.obj;
            window.$docsify = {homepage: mdFileUrl}
        })
    })
</script>

正文完
 0