1. 使用脚手架生成项目 #

cnpm i egg-init -g
egg-init  zhufengpeixunblog-api --type simple
cd zhufengpeixunblog-api
cnpm i

cnpm run dev
opoen localhost:7001

2. 编写用户注册功能 #

3.1.2 启用插件 #

// {app_root}config\plugin.js

exports.mongoose = {
    enable: true,
    package: 'egg-mongoose'
}

3.1.3 配置插件 #

// {app_root}/config/config.default.js

exports.mongoose = {
  client: {
    url: 'mongodb://127.0.0.1/zhufengpeixunblog',
    options: {},
  },
};

2.2 配置模型 #

// {app_root}/app/model/user.js

module.exports = app => {
    const mongoose = app.mongoose;
    const Schema = mongoose.Schema;
    const ObjectId = Schema.Types.ObjectId;
    const UserSchema = new Schema({
        username: { type: String, required: true },
        password: { type: String, required: true },
        email: String
    });
    return mongoose.model('User', UserSchema);
}

2.3 控制器中使用 #

const BaseControler = require('./base');
class UserController extends BaseControler {
    //用户注册
    async signup() {
        let { ctx, app } = this;
        let user = ctx.request.body;
        try {
            user = await ctx.model.User.create(user);
            this.success(user);
        } catch (error) {
            this.error(error);
        }
    }
}

2.4 配置路由 #

module.exports = app => {
  const { router, controller } = app;
  router.post('/api/users/signup', controller.users.signup);
};

2.5 暂时禁用CSRF #

config\config.default.js

  config.security = {
    csrf: false
  }

3. 编写用户登录功能 #

3.1 控制器上增加方法 #

    //用户登录
    async signin() {
        let { ctx, app } = this;
        let user = ctx.request.body;
        try {
            user = await ctx.model.User.findOne(user);
            if (user) {
                ctx.session.user = user;//保持会话
                this.success({ user });
            } else {
                this.error('用户名或密码错误');
            }
        } catch (error) {
            this.error(error);
        }
    }

3.2 配置路由 #

 router.post('/api/users/signin', controller.users.signin);

4. 编写用户退出功能 #

4.1 控制器上增加方法 #

async signout() {
        let { ctx } = this;
        ctx.session.user = null;
        this.success('success');
}

4.2 配置路由 #

 router.get('/api/users/signout', controller.users.signout);

5. 分类管理 #

Method Path Controller.Action
POST /posts app.controllers.posts.create
GET /posts app.controllers.posts.index
PUT /posts/:id app.controllers.posts.update
DELETE /posts/:id app.controllers.posts.destroy

\app\router.js

router.resources('categories', '/api/categories', controller.categories);

app\model\category.js

module.exports = app => {
    const mongoose = app.mongoose;
    const Schema = mongoose.Schema;
    const ObjectId = Schema.Types.ObjectId;
    const CategorySchema = new Schema({
        name: { type: String, required: true }
    });
    return mongoose.model('Category', CategorySchema);
}

5.1 添加分类 #

    async create() {
        let { ctx } = this;
        let category = ctx.request.body;
        try {
            let doc = await ctx.model.Category.create(category);
            this.success('success');
        } catch (err) {
            this.error(error);
        }
    }

5.2 查看分类列表 #

 //查询分类列表
    async index() {
        let { ctx } = this;
        let { pageNum = 1, pageSize = 10, keyword } = ctx.query;
        pageNum = isNaN(pageNum) ? 1 : parseInt(pageNum);
        pageSize = isNaN(pageSize) ? 1 : parseInt(pageSize);
        let query = {};
        if (keyword) {
            query.name = new RegExp(keyword);
        }
        let total = await ctx.model.Category.count(query);
        let items = await ctx.model.Category.find(query).skip((pageNum - 1) * pageSize).limit(pageSize);
        this.success({
            items,
            pageNum,
            pageSize,
            total,
            pageCount: Math.ceil(total / pageSize)
        });
    }

5.3 修改分类 #

 //修改分类
    async update() {
        let { ctx } = this;
        let id = ctx.params.id;
        let category = ctx.request.body;
        try {
            let result = await ctx.model.Category.findByIdAndUpdate(id, category);
            this.success('success');
        } catch (err) {
            this.error(error);
        }
    }

5.4 删除分类 #

 //删除分类
    async destroy() {
        let { ctx } = this;
        let id = ctx.params.id;
        let { ids = [] } = ctx.request.body;
        ids.push(id);
        try {
            await ctx.model.Category.remove({ _id: { $in: ids } });
            this.success('success');
        } catch (error) {
            this.error(error);
        }
    }

6. 文章管理 #

\app\router.js

router.resources('articles', '/api/articles', controller.articles);
router.get('/api/articles/pv/:id', controller.articles.updatePv);
router.post('/api/articles/comment/:id', controller.articles.comment);

app\model\article.js

module.exports=app => {
    const mongoose=app.mongoose;
    const Schema=mongoose.Schema;
    const ObjectId=Schema.Types.ObjectId;
    const ArticleSchema=new Schema({
        user: {type: ObjectId,ref: 'User'},
        category: { type: ObjectId, ref: 'Category' },
        title: String,
        content: String,
        pv: { type: Number, default: 0 },
        comments: [{ user: { type: ObjectId, ref: 'User' }, content: String, createAt: { type: Date, default: Date.now } }],
        createAt: { type: Date, default: Date.now }
    });
    return mongoose.model('Article',ArticleSchema);
}

6.1 添加文章 #

  async create() {
    let { ctx } = this;
    let article = ctx.request.body;
    article.user = this.user._id;
    try {
      let doc = await ctx.model.Article.create(article);
      this.success('success');
    } catch (error) {
      this.error(error);
    }
  }

6.2 查看文章列表 #

async index() {
    let { ctx } = this;
    let { pageNum = 1, pageSize = 10, keyword } = ctx.query;
    pageNum = isNaN(pageNum) ? 1 : parseInt(pageNum);
    pageSize = isNaN(pageSize) ? 1 : parseInt(pageSize);
    let query = {};
    if (keyword) {
      query.title = new RegExp(keyword);
    }
    let total = await ctx.model.Article.count(query);
    let items = await ctx.model.Article.find(query).populate('category').populate('comments').skip((pageNum - 1) * pageSize).limit(pageSize);
    this.success({
      items,
      pageNum,
      pageSize,
      total,
      pageCount: Math.ceil(total / pageSize)
    });
  }

6.3 修改文章 #

 async update() {
    let { ctx } = this;
    let id = ctx.params.id;
    let article = ctx.request.body;
    try {
      let result = await ctx.model.Article.findByIdAndUpdate(id, article);
      this.success('success');
    } catch (err) {
      this.error(error);
    }
  }

6.4 删除文章 #

  async destroy() {
    let { ctx } = this;
    let { ids } = ctx.request.body;
    try {
      await ctx.model.Article.remove({ _id: { $in: ids } });
      this.success('success');
    } catch (error) {
      this.error(error);
    }
  }

6.5 修改阅读量 #

  async updatePv() {
    let { ctx } = this;
    let id = ctx.params.id;
    try {
      let result = await ctx.model.Article.findByIdAndUpdate(id, { $inc: { pv: 1 } });
      this.success('success');
    } catch (error) {
      this.error(error);
    }
  }

6.6 评论文章 #

  async comment() {
    let { ctx } = this;
    let id = ctx.params.id;
    let comment = ctx.request.body;
    comment.user = this.user._id;;
    try {
      let result = await ctx.model.Article.findByIdAndUpdate(id, { $push: { comments: comment } });
      this.success('success');
    } catch (err) {
      this.error(error);
    }
  }

7. 处理跨域 #

8. 会话持久化 #

// {app_root}/config/plugin.js

exports.sessionRedis = {
  enable: true,
  package: 'egg-session-redis',
};

exports.redis = {
  enable: true,
  package: 'egg-redis',
}

// {app_root}/config/config.default.js

exports.redis = {
  client: {
    host: '127.0.0.1',
    port: '6379',
    password: 'zfpx',
    db: '0',
  },
  agent:true
};

9. 开发 #

9.1 指定运行环境 #

EGG_SERVER_ENV=prod
app.config.env
config
|- config.default.js
|- config.test.js
|- config.prod.js
|- config.unittest.js
`- config.local.js

附录 #