SpringBoot集成markdown实现文档管理

简介: 最近在做一个部门内部简单的知识库系统,便于新人入职了解与一些常见问题的解答,知识库的形式是以文档为主,为了快速实现文档功能,决定采用markdown形式录入,生成本地文件后以html方式展现,层次清晰便于查看

背景

最近在做一个部门内部简单的知识库系统,便于新人入职了解与一些常见问题的解答,知识库的形式是以文档为主,为了快速实现文档功能,决定采用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>

目录
相关文章
|
4月前
|
监控 druid Java
spring boot 集成配置阿里 Druid监控配置
spring boot 集成配置阿里 Druid监控配置
287 6
|
4月前
|
Java 关系型数据库 MySQL
如何实现Springboot+camunda+mysql的集成
【7月更文挑战第2天】集成Spring Boot、Camunda和MySQL的简要步骤: 1. 初始化Spring Boot项目,添加Camunda和MySQL驱动依赖。 2. 配置`application.properties`,包括数据库URL、用户名和密码。 3. 设置Camunda引擎属性,指定数据源。 4. 引入流程定义文件(如`.bpmn`)。 5. 创建服务处理流程操作,创建控制器接收请求。 6. Camunda自动在数据库创建表结构。 7. 启动应用,测试流程启动,如通过服务和控制器开始流程实例。 示例代码包括服务类启动流程实例及控制器接口。实际集成需按业务需求调整。
363 4
|
4月前
|
消息中间件 Java 测试技术
【RocketMQ系列八】SpringBoot集成RocketMQ-实现普通消息和事务消息
【RocketMQ系列八】SpringBoot集成RocketMQ-实现普通消息和事务消息
317 1
|
5月前
|
消息中间件 Java Kafka
springboot集成kafka
springboot集成kafka
168 2
|
5月前
|
消息中间件 Java Kafka
集成Kafka到Spring Boot项目中的步骤和配置
集成Kafka到Spring Boot项目中的步骤和配置
259 7
|
5月前
|
druid Java 关系型数据库
在Spring Boot中集成Druid实现多数据源有两种常用的方式:使用Spring Boot的自动配置和手动配置。
在Spring Boot中集成Druid实现多数据源有两种常用的方式:使用Spring Boot的自动配置和手动配置。
785 5
|
5月前
|
Java 数据库连接 mybatis
在Spring Boot应用中集成MyBatis与MyBatis-Plus
在Spring Boot应用中集成MyBatis与MyBatis-Plus
123 5
|
5月前
|
前端开发 JavaScript 安全
集成WebSocket在Spring Boot中可以用于实现实时的双向通信
集成WebSocket在Spring Boot中可以用于实现实时的双向通信
86 4
|
5月前
|
监控 前端开发 Java
五分钟后,你将学会在SpringBoot项目中如何集成CAT调用链
五分钟后,你将学会在SpringBoot项目中如何集成CAT调用链
|
4月前
|
消息中间件 Java Kafka
Spring Boot与Apache Kafka Streams的集成
Spring Boot与Apache Kafka Streams的集成