<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          egg+vue+mongodb實(shí)踐開(kāi)發(fā)在線文檔管理平臺(tái)——水墨文檔

          共 23303字,需瀏覽 47分鐘

           ·

          2021-01-28 21:50


          授權(quán)轉(zhuǎn)載自:圍的圍

          https://segmentfault.com/a/1190000037621367

          前言

          團(tuán)隊(duì)中會(huì)遇到在線文檔管理的需求,包括技術(shù)文檔,接口文檔, excel 文檔,和產(chǎn)品原型的托管等需求,一直沒(méi)有找到合適的開(kāi)源項(xiàng)目來(lái)滿足需求,所以動(dòng)手實(shí)現(xiàn)了個(gè)文檔管理系統(tǒng)(實(shí)現(xiàn)起來(lái)并不復(fù)雜,該教程只是提供思路,并非最佳實(shí)踐)

          Github: https://github.com/huangwei9527/Ink-wash-docs

          演示地址:http://www.inkwash.online/

          功能列表

          • [x] 登錄注冊(cè)
          • [x] 工作臺(tái)|文檔列表
          • [x] 文檔編輯預(yù)覽(支持:md, excel,html產(chǎn)品原型托管)
          • [x] 協(xié)作編輯
          • [x] 訪問(wèn)權(quán)限設(shè)置
          • [x] 團(tuán)隊(duì)管理
          • [x] 點(diǎn)贊收藏
          • [x] 模板管理
          • [x] 瀏覽歷史
          • [x] 回收站
          • [ ] 文件夾形式閱讀(接口文檔)
          • [ ] 編輯歷史版本

          系統(tǒng)界面預(yù)覽

          閱讀前準(zhǔn)備

          1、了解 vue 技術(shù)棧開(kāi)發(fā) 2、了解 koa3、了解 egg4、了解 mongodb

          技術(shù)棧

          前端:vue: 模塊化開(kāi)發(fā)少不了angular,react,vue三選一,這里選擇了vue。vuex: 狀態(tài)管理sass: css預(yù)編譯器element-ui:不造輪子,有現(xiàn)成的優(yōu)秀的vue組件庫(kù)當(dāng)然要用起來(lái)。

          服務(wù)端:egg.js:企業(yè)級(jí)框架,按照一套統(tǒng)一的約定進(jìn)行應(yīng)用開(kāi)發(fā),開(kāi)發(fā)十分高效。mongodb:一個(gè)基于分布式文件存儲(chǔ)的數(shù)據(jù)庫(kù),比較靈活。egg-alinode:阿里提供的免費(fèi)nodejs服務(wù)器性能監(jiān)控。

          工程搭建

          這里我們將前后端項(xiàng)目放在同一個(gè)目錄下管理,分別用 egg 腳手架和 vue-cli3 生成初始化項(xiàng)目,拷貝合并到同一個(gè)目錄下,記得合并下 package.json 內(nèi)容。(腳手架生成項(xiàng)目就不介紹了,按照文檔來(lái)就是了),合并后將 vue 項(xiàng)目 src 目錄改為 web ,如下:

          ···
          ·
          |-- app                    // egg 初始化app目錄
          |-- config                // egg 初始化app目錄
          |-- public                // vue 靜態(tài)資源目錄
          |-- web                    // 原 src 目錄,改成 web 用作前端項(xiàng)目目錄
          ·
          ···

          這樣的話 我們需要再把我們vue webpack打包配置稍作一下調(diào)整,首先是把原先的編譯指向src的目錄改成 web,其次為了 npm run build 能正常編譯 web 我們也需要為 babel-loader 再增加一個(gè)編譯目錄

          • 根目錄新增 vue.config.js ,目的是為了改造 vue 項(xiàng)目入口,改為: web/main.js

            module.exports = {    
                pages: {        
                    index: {            
                        entry: "web/main.js"        
                    }    
                }
            }
          • babel-loader 能正常編譯 web 目錄, 在 vue.config.js 新增如下配置

          // 擴(kuò)展 webpack 配置
          chainWebpackconfig => {
              config.module
              .rule('js')
              .include.add(/web/).end()
              .use('babel')
              .loader('babel-loader')
              .tap(options => {
              // 修改它的選項(xiàng)...
              return options
              })
          }
          • package.json 新增前端項(xiàng)目打包命令
          "dev-web""vue-cli-service serve",
          "build-web""vue-cli-service build",

          至此前后端項(xiàng)目初始化工作就完了,前端開(kāi)發(fā)啟動(dòng)npm run dev-web 后端開(kāi)發(fā)啟動(dòng) npm run dev

          工程目錄結(jié)構(gòu)

          |-- app                    --------服務(wù)器端項(xiàng)目代碼
              |--controller                --------用于解析用戶的輸入,處理后返回相應(yīng)的結(jié)果
              |--extend                    --------框架的擴(kuò)展
              |--middleware                --------編寫中間件
              |--model                    --------Schema數(shù)據(jù)模型
              |--public                    --------用于放置靜態(tài)資源
              |--service                    --------用于編寫業(yè)務(wù)邏輯層
              |--router.js                --------用于配置 URL 路由規(guī)則
          |-- config                    --------egg 配置文件
              |--config.default.js            --------默認(rèn)配置
              |--config.local.js                --------開(kāi)發(fā)環(huán)境配置
              |--config.prod.js                --------生產(chǎn)環(huán)境配置
              |--plugin.js                    --------配置需要加載的插件
          |-- web                        --------前端項(xiàng)目界面代碼
              |--common                    --------前端界面對(duì)應(yīng)靜態(tài)資源
              |--components                --------組件
              |--config                    --------配置文件
              |--filter                    --------過(guò)濾器
              |--pages                    --------頁(yè)面
              |--router                    --------路由配置
              |--store                    --------vuex狀態(tài)管理
              |--service                    --------axios封裝
              |--App.vue                    --------App
              |--main.js                    --------入口文件
              |--permission.js            --------權(quán)限控制
          |-- docs                    --------預(yù)留編寫項(xiàng)目文檔目錄
          |-- vue.config.js            --------vue webpack配置文件
          |-- package.json
          ...
          ...

          完成項(xiàng)目目錄初始化后,接下來(lái)先把 mongodb 全局得一些中間件、擴(kuò)展方法給配置上,為接口開(kāi)發(fā)做好準(zhǔn)備工作

          mongodb配置

          1、安裝 mongoose模塊

          npm install egg-mongoose --save

          2、配置 config 文件

          // config/plugin.js
          exports.mongoose = {
              enabletrue,
              package'egg-mongoose',
          };

          // config/config.default.js
          config.mongoose = {
              url'mongodb://127.0.0.1:27017/inkwash',
              options: {},
          };

          全局中間件和擴(kuò)展配置

          1、統(tǒng)一處理接口

          后端接口開(kāi)發(fā)中我們需要一個(gè)統(tǒng)一得返回格式,可以在 context 對(duì)象下擴(kuò)展個(gè)返回?cái)?shù)據(jù) function 用于統(tǒng)一處理接口 response data

          app 下新建文件夾 extend 新建 context.js

          // app/extend/context.js
          module.exports = {
              /**
               * 返回客戶端的內(nèi)容
               * @param status // 接口是否成功
               * @param body // 返回?cái)?shù)據(jù)
               * @param msg // 返回信息提示
               * @param code // 返回狀態(tài)碼
               */

              returnBody (status = true, body = {}, msg = 'success', code = 200) {
                  this.status = code;
                  this.body = {
                      status: status,
                      body: body,
                      msg,
                      code: code
                  }
              }
          }
          // 調(diào)用
          const { ctx } = this;
          ctx.returnBody(true, {}, "成功");

          2、添加統(tǒng)一處理錯(cuò)誤得中間件

          app文件夾下新建 middleware 文件夾,新建 error_handler.js , 并配置 congfig 全局中間件配置

          // app/middleware/error_handler.js
          module.exports = () => {

              return async function errorHandler(ctx, next{
                  try {
                      await next();
                  } catch (err) {
                      // 所有的異常都會(huì)在app上出發(fā)一個(gè)error事件,框架會(huì)記錄一條錯(cuò)誤日志
                      ctx.app.emit('error', err, ctx);

                      const status = err.status || 500;

                      // 如果時(shí)生產(chǎn)環(huán)境的時(shí)候 500錯(cuò)誤的詳細(xì)錯(cuò)誤內(nèi)容不返回給客戶端
                      const error = status === 500 && ctx.app.config.env === 'prod' ? '網(wǎng)絡(luò)錯(cuò)誤' : err.message;

                      ctx.body = {
                          msg: error,
                          statusfalse,
                          body: {},
                          code: status
                      };
                  }
              };
          };

          // app/middleware/error_handler.js
          // config/config.default.js 配置全局中間件
          config.middleware = [ 'errorHandler'];

          jwt鑒權(quán)登錄認(rèn)證

          1、安裝 egg-jwt token生成以及驗(yàn)證包

          npm install egg-jwt --save

          2、安裝完成后在根目錄下的 config/plugin.js 配置一下,如:

          'use strict';

          /** @type Egg.EggPlugin */
          module.exports = {
              jwt: {
                  enabletrue,
                  package"egg-jwt"
              },
            mongoose: {
              enabletrue,
              package'egg-mongoose',
            }
          };

          3、接下來(lái)在 config/config.default.js 里面繼續(xù)配置:

          config.jwt = {
            secret"123456"//自定義 token 的加密條件字符串
          };

          4、在 context 上擴(kuò)展兩個(gè) function , getTokencheckToken 用于生成 token 和驗(yàn)證 token

          // app/extend/context.js
          async getToken(data) {
              return await this.app.jwt.sign(data, this.app.config.jwt.secret, {expiresIn3024 * 60 * 60 + 's'});
          },
          async checkToken(token) {
              return await this.app.jwt.verify(token, this.app.config.jwt.secret)
          }

          5、編寫個(gè)中間件實(shí)現(xiàn)登錄驗(yàn)證攔截 在 app/middleware 文件夾下新建 auth.js

          // app/middleware/auth.js
          module.exports = () => {
              return async function(ctx, next{
                  let token = '';
                  if (
                      ctx.headers.authorization && ctx.headers.authorization.split(' ')[0] === 'Bearer'
                  ) {
                      token = ctx.headers.authorization.split(' ')[1];
                  } else if (ctx.query.accesstoken) {
                      token = ctx.query.accesstoken;
                  } else if (ctx.request.body.accesstoken) {
                      token = ctx.request.body.accesstoken;
                  }
                  let user;
                  try{
                      user = await ctx.checkToken(token);
                  }catch (e) {
                      ctx.returnBody(false,{}, 'Token 無(wú)效,請(qǐng)重新登錄'401);
                  }
                  if (!user) {
                      ctx.returnBody(false,{}, 'Token 無(wú)效,請(qǐng)重新登錄'401);
                      return;
                  }
                  ctx.request.user = user;
                  await next();
              };
          };

          好了以上配置完成后就開(kāi)始接下來(lái)的核心注冊(cè)功能相關(guān)操作了。

          • 首先我在根目錄下的 app/router.js 創(chuàng)建訪問(wèn)路由:
          import { Application } from 'egg';

          export default (app: Application) => {
            const { controller, router, jwt } = app;
            //正常路由
            router.post('/auth/register', controller.auth.register);
            
            // 只有在需要驗(yàn)證 token 的路由上添加jwt
            router.post('/user/infor',jwt, controller.user.infor); 
          };
          • 接下來(lái)我去編寫我的控制器,在根目錄下的 app/controller/home.ts 編寫內(nèi)容:這里使用了兩個(gè)我們?cè)?app/extend/context.js 上擴(kuò)展的兩個(gè)通用方法
            1. 通過(guò) ctx.getToken (用戶信息 object 對(duì)象)將用戶信息通過(guò) jwt 生成 token 返回給前端
            2. 通過(guò) ctx.returnBody 返回?cái)?shù)據(jù)
          // app/controller/auth.js
          const Controller = require('egg').Controller
          class AuthController extends Controller {
              async login() {
                  //... 略
              }
              async register() {
                  const { ctx, service } = this;
                  const { username, password, email } = ctx.request.body
                  let userData = await ctx.service.user.createUser(username, password, email);
                  userData = userData.toObject();
                  let userDataStr = JSON.parse(JSON.stringify(userData));
                  // 生成token
                  let token =await ctx.getToken(userDataStr);
                  ctx.returnBody(true, {access_token: token, userInfo: userData}, "注冊(cè)成功!")
              }
          }

          module.exports = AuthController;
          • 前端請(qǐng)求的時(shí)候需要在 headers 里面上默認(rèn)的驗(yàn)證字?jǐn)?Authorization 就可以了,如:
          axios({
           method'get',
            url'http://127.0.0.1:7001/user/info',
            headers:{
                // 切記 token 不要直接發(fā)送,要在前面加上 Bearer 字符串和一個(gè)空格
              'Authorization':`Bearer ${token}`
            }
          })
          • 接口從 token 獲取加密信息
          1. app/extend/context.js 再擴(kuò)展個(gè) getUser 方法獲取 token 加密信息
          // app/extend/context.js
          // 獲取用戶信息
              async getUserData() {
                  var token = this.headers.authorization ? this.headers.authorization : '';
                  token = token.substring(7//把Bearer 截取掉,解析的時(shí)候不需要加上Bearer
                  let user = {}
                  try {
                      user = this.app.jwt.verify(token, this.app.config.jwt.secret);
                  } catch (err) {
                      user = {}
                  }
                  return user;
              }
          1. 實(shí)現(xiàn)獲取個(gè)人信息接口
          // app/controller/user.js
          'use strict';

          const Controller = require('egg').Controller;

          class UserController extends Controller {
              async info() {
                  let {ctx} = this;
                  let user = await this.ctx.getUserData()
                  ctx.returnBody(true, user)
              }
          }

          module.exports = UserController;

          至此我們就實(shí)現(xiàn)了 jwt 生成 token , 然后通過(guò)前端傳過(guò)來(lái)的 token 獲取當(dāng)前登錄用戶的信息,  jwt 登錄授權(quán)這塊應(yīng)該是講完了,其他的業(yè)務(wù)接口應(yīng)該實(shí)現(xiàn)起來(lái)難度不大

          md文檔編輯

          文檔編輯器使用 Vdito r, 一款瀏覽器端的 Markdown 編輯器,支持所見(jiàn)即所得(富文本)、即時(shí)渲染(類似 Typora )和分屏預(yù)覽模式 安裝 Vditor

          npm install vditor --save

          在代碼中引入并初始化對(duì)象

          <template>
            <div class="editor-component editor-md" ref="editor-component">
              <div id="editor-md-dom"></div>
            </div>

          </template>

          <script>
              import Vditor from 'vditor'
              import "vditor/
          src/assets/scss/index.scss"

              let timer = null;
              export default {
                   data(){
                       return {
                          contentEditor: '',
                      }
                    },
                    mounted () {
                      this.contentEditor = new Vditor('vditor', {
                        height: 360,
                        toolbarConfig: {
                          pin: true,
                        },
                        cache: {
                          enable: false,
                        },
                        after: () => {
                          this.contentEditor.setValue('hello, Vditor + Vue!')
                        },
                      })
                   },
              }
          </script>

          excel表格編輯

          安裝 x-data-spreadsheet

          npm install x-data-spreadsheet
          <div id="x-spreadsheet-demo"></div>
          import Spreadsheet from "x-data-spreadsheet";
          // If you need to override the default options, you can set the override
          // const options = {};
          // new Spreadsheet('#x-spreadsheet-demo', options);
          const s = new Spreadsheet("#x-spreadsheet-demo")
            .loadData({}) // load data
            .change(data => {
              // save data to db
            });
           
          // data validation
          s.validate()

          axure原型托管

          原型 axure 頁(yè)面托管,參考 WuliHub 讓用戶上傳生成的 html 壓縮包,然后解壓到靜態(tài)資源目錄,返回訪問(wèn)地址就 ok , 前端拿到原型地址用內(nèi)嵌 iframe 渲染出來(lái)就 ok

          打包編譯&&靜態(tài)資源設(shè)置

          1、配置前端 vue 頁(yè)面打包命令

          // kage.json script新增打包命令
          "build-web": "vue-cli-service build",

          2、運(yùn)行 npm run build-web  根目錄會(huì)生成 dist 前端代碼靜態(tài)文件,因?yàn)?egg 支持設(shè)置多個(gè)靜態(tài)資源目錄,這里就直接配置根目錄下的dist 文件夾為靜態(tài)目錄, 配置 config

          // config/config.default.js
          config.static = {
                  prefix'/',// 將靜態(tài)資源前綴改為'/'(默認(rèn)是 '/public')
                  dir: [
                      path.join(__dirname, '../app/public'), 
                      path.join(__dirname, '../dist')
                  ]
              }

          打包完成后啟動(dòng) egg , 就可以通過(guò) http://localhost/:7001/index.html 訪問(wèn)到前端頁(yè)面了


          因?yàn)橹苯釉L問(wèn) http://localhost/:7001 會(huì) 404可以再配置個(gè)路由重定向,將跟路由 '/' 重定向到 '/index.html'

          // app/router.js 
          // 重定向到index頁(yè)面
          app.router.redirect('/''/index.html'302);

          部署

          服務(wù)端部署運(yùn)行 start 命令

          npm run start

          性能監(jiān)控

          node 服務(wù)性能監(jiān)控這塊可以使用阿里免費(fèi)開(kāi)源的 alinode1、安裝 egg-alinode

          npm i egg-alinode

          2、插件配置

          // config/plugin.js
          exports.alinode = {
            enabletrue,
            package'egg-alinode',
          };

          3、配置config

          // config/config.default.js
          exports.alinode = {
            enabletrue,
            appid'my app id',
            secret'my app secret',
          };

          這樣就可以了,監(jiān)控?cái)?shù)據(jù)可以在阿里 Node.js 性能平臺(tái)控制臺(tái)看到監(jiān)控面板

          聲明:文章著作權(quán)歸作者所有,如有侵權(quán),請(qǐng)聯(lián)系小編刪除。



          最后


          • 歡迎加我微信(winty230),拉你進(jìn)技術(shù)群,長(zhǎng)期交流學(xué)習(xí)...

          • 歡迎關(guān)注「前端Q」,認(rèn)真學(xué)前端,做個(gè)專業(yè)的技術(shù)人...

          點(diǎn)個(gè)在看支持我吧
          瀏覽 34
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天日天天舔天天射 | 第九色| 91麻豆产精品久久久久久 | www.777久久 | 韩国成人无码 |