• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

vue-koa2: vue2,koa2和mongo搭建的单用户博客

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称:

vue-koa2

开源软件地址:

https://gitee.com/gfzl-open-source/vue-koa2

开源软件介绍:

vue-koa2 server篇

vue2,koa2和mongo搭建的单用户博客

目录设计

  • app.js -------- 入口文件
  • models -------- 数据库模型
  • controllers --------- 完成逻辑处理的控制器
  • middlewares --------- 自己封装的中间件
  • routes --------- 路由
  • utils --------- 工具函数
  • configs -------- 配置文件
  • package.json --------- 项目所需依赖好的目录设计有利于后期的维护,有规有矩,自己看起来也清爽许多。路由部分必须和控制器分开,这样能做控制器只需关心实现该有的业务逻辑。

用class+async/await写控制器

class+async/await的结合,可以使得我们更好的组织api的逻辑层,语义和结构都会更加清晰。这样做就不用写一个逻辑处理函数都exports一次。直接暴露一个class出去就可以了。async函数作为class的静态方法,所有我们可以直接className.[xxx]来访问这些控制器。

先上代码:

# 逻辑层来自server/controllers/article.jsconst Article = require('../models/article.js');class ArticleController{    //创建文章    static async createArticle(ctx, next){...}    //发布文章    static async ifPublishArticle(ctx){...}    //删除文章    static async deleteArticleById(ctx){...}    //修改文章    static async modifyArticle(ctx){...}    //获取所有文章    static async getAllArticles(ctx){...}    //获取所以已发布的文章    static async getAllPublishedArticles(ctx){...}}exports = module.exports = ArticleController;
# 接口层(来自server/routes/index.js)//引入class这个类const A = require('../controllers/article.js');router    .get('/articles/:id', A.getArticleById)                          .post('/articles', checkToken, A.createArticle)                             .delete('/articles/:id', checkToken, A.deleteArticleById)                     .patch('/articles/:id', checkToken, A.modifyArticle)                          .get('/allArticles', checkToken, A.getAllArticles)                          .get('/articles', A.getAllPublishedArticles)                          .patch('/pubArticles/:id', checkToken, A.ifPublishArticle)                   .post('/tags', checkToken, T.createTag)                                      .get('/tags', T.getAllTags)                                        .patch('/tags/:id', checkToken, T.modifyTag)                                  .delete('/tags/:id', checkToken, T.deleteTag)       

如何使用koa2+es6/7打造高质量Restful API详细版本

鉴权jsonwebtoken

鉴权其实很简单,登录的时候给予前端token,前端利用axios的拦截器即可使得所有请求都将携带token上来。利用jsonwebtoken这个模块,在封装一个checktoken中间件,就能完成权限的鉴定。

# 实例(来自server/routes/index.js)router    //修改单个标签    .patch('/tags/:id', checkToken, T.modifyTag)    //删除单个标签    .delete('/tags/:id', checkToken, T.deleteTag)                           

看上面的代码,有没有发现,想要修改标签,必须经过checkToken这个中间件,如果checkToken没有向下next(),那么T.modifyTag是没办法执行的。利用这一点,我们利用checkToken对请求进行鉴定,如果没有token或者token过期,那就没办法修改了。鉴权的代码位置: server/middlewares/checkToken.jsserver/utils/index.js

封装一个统一相应处理中间件

为什么想写一个统一相应处理的中间件呢?其实这个中间件只是都koa2的ctx.body的再加上一层的封装,直接使用ctx.body和ctx.throw是没问题的。我主要用来它来实现自定义的错误状态码,还有一点好处是能保证输出到前端的数据格式能够单一。

// use: 用来给所有请求统一响应--统一响应中间件---要在使用其他中间件之前使用//在ctx对象上挂载方法,如果在调用的是有些参数没有出入,那么相当这个参数不存在,除非采用默认值的方式module.exports = async (ctx, next) => {    //请求成功时    ctx.success = ({ data, msg, total, success}) => {        ctx.body = { code: 200, data, msg, total, success };    };    await next();};

文章的日期格式化处理

moment+mogoose的虚拟属性即可完成自定义的时期格式。

# 时期格式化处理const moment = require('moment');moment.locale('zh-cn');//必须先set后getarticleSchema.set('toJSON', { getters: true, virtuals: true });articleSchema.set('toObject', { getters: true, virtuals: true });articleSchema.path('createTime').get(function(v) {  return moment(v).format('YYYY MMMM Do, h:mm:ss a');});articleSchema.path('lastEditTime').get(function(v) {  return moment(v).format('YYYY MMMM Do, h:mm:ss a');});

当我们在控制器里面存日期的时候,直接new Date()存入即可,当我们在取出数据时,mogoose的虚拟属性,先做格式化处理再取出来。

mongoose的ref

我们知道mongoDB是noSQL数据库,如果我们想也能用其他文档。那么ref+population即可做到。

const articleSchema = new Schema({    .....    tags: [{ type: Schema.Types.ObjectId, ref: 'tag' }]  //type为tag文档的id});

看,我在定义articleSchema的时候,我把它的tags字段定义成数组,数组存放的时候各个tag的_id。如果我按平时那样去数据,即只能拿到 { title : '标题', ..., tags: ['21312321323', '1231231232313']}类似这样的东西,但如果利用population来取数据

result = await Article                .find({})                .populate('tags')                .exec()

那么会得到{ title : '标题', ..., tags: ['标签1', '标签2']},而不是单纯的tagId了。mogoose学习进阶

分页查询

当前台在查询文章时,一般不是一次性返回全部文章,而是通过分段来查询文章。对于数据量不大的博客,我直接用page和limit这两个请求参数来查询文章。如www.xxx.com/api?page=1&&limit=5来请求第一页的数据,每页按5条来分。

 let page = +ctx.query.page;let limit = +ctx.query.limit || 5;result = await Article                .find()                .sort({ 'createTime': -1 })                .skip(limit * (page - 1))                .limit(limit)                .populate('tags')                .exec()                .catch(err => {                    ctx.throw(500, '服务器内部错误-分页查找错误!');                });

想做进一步的优化,请看下面的文章mongodb分页优化

自定义配置

# 可以在configs目录下新建private.js来配置对象格式要一致let config = {   admin: {       username: 'admin',                  password: 'admin'   },   jwt: {       secret: 'secret',                   exprisesIn: '3600s'          //以秒为单位   },   mongodb: {       host: '127.0.0.1',       database: 'blog',       port: 27017,       user: '',                    //非必填       password: ''                 //非必填   },   app: {       port: process.env.PORT || 3000,       routerBaseApi: '/api'   }};

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap