Egg.js+sequelize学习之路

本文介绍了如何使用Egg.js和sequelize搭建Node.js项目,包括环境配置、数据库连接、模型创建、业务逻辑接口编写、路由设置、字段验证以及定时任务的实现。详细讲解了从初始化项目到完成用户表CURD操作的过程。

一、Egg 快速入门、搭建环境、创建项目

环境准备

操作系统:支持 macOS,Linux,Windows

运行环境:Nodejs 建议选择 LTS 版本,Nodejs 最低要求 8.x。

安装 egg 脚手架以及使用 egg-init 创建项目

推荐直接使用脚手架,只需几条简单指令,即可快速生成项目:

$ npm i egg-init -g
$ mkdir hello-egg
$ cd hello-egg
$ egg-init hello-egg --type=simple 
$ cd hello-egg
$ npm i
启动项目:
$ npm run dev
$ open http://127.0.0.1:7001/

二、项目使用sequelize连接数据库mysql

安装并配置 egg-sequelize 插件(它会辅助我们将定义好的 Model 对象加载到 app 和 ctx 上)和 mysql2 模块:

安装

cnpm install --save egg-sequelize mysql2
  • 在 config/plugin.js 中引入 egg-sequelize 插件
'use strict';

/** @type Egg.EggPlugin */
module.exports.sequelize = {
  // had enabled by egg
  // static: {
  //   enable: true,
  // }
  enable: true,
  package: 'egg-sequelize',
};
  • 在 config/config.default.js 中编写 sequelize 配置
/* eslint valid-jsdoc: "off" */

'use strict';

/**
 * @param {Egg.EggAppInfo} appInfo app info
 */
module.exports = appInfo => {
  /**
   * built-in config
   * @type {Egg.EggAppConfig}
   **/
  const config = exports = {};

  // use for cookie sign key, should change to your own and keep security
  config.keys = appInfo.name + '_1610673778973_1712';

  // add your middleware config here
  config.middleware = [];
  // add your user config here
  const userConfig = {
    // myAppName: 'egg',
  };
  config.sequelize = {
    dialect: 'mysql',
    host: '127.0.0.1',
    port: 3306,
    database: 'redmark',
    username: 'root',
    password: 'mysql123',
  };

  return {
    ...config,
    ...userConfig,
  };
};

初始化数据库和 Migrations

  • 安装 sequelize-cli
cnpm install --save-dev sequelize-cli

在 egg 项目中,我们希望将所有数据库 Migrations 相关的内容都放在 database 目录下,所以我们在项目根目录下新建一个 .sequelizerc 配置文件:

'use strict';

const path = require('path');

module.exports = {
  config: path.join(__dirname, 'database/config.json'),
  'migrations-path': path.join(__dirname, 'database/migrations'),
  'seeders-path': path.join(__dirname, 'database/seeders'),
  'models-path': path.join(__dirname, 'app/model'),
};
  • 初始化 Migrations 配置文件和目录
npx sequelize init:config
npx sequelize init:migrations

执行完后会生成 database/config.json 文件和 database/migrations 目录,我们修改一下 database/config.json 中的内容,将其改成我们项目中使用的数据库配置

此时 sequelize-cli 和相关的配置也都初始化好了,我们可以开始编写项目的第一个 Migration 文件来创建我们的一个 users 表了。

npx sequelize migration:generate --name=init-users

执行完后会在 database/migrations 目录下生成一个 migration 文件(${timestamp}-init-users.js),我们修改它来处理初始化 users 表

'use strict';

module.exports = {
  up: async (queryInterface, Sequelize) => {
    const { INTEGER, DATE, STRING } = Sequelize;
    await queryInterface.createTable('users', {
      id: { type: INTEGER, primaryKey: true, autoIncrement: true },
      name: STRING(30),
      age: INTEGER,
      created_at: DATE,
      updated_at: DATE,
    });
  },
  down: async queryInterface => {
    await queryInterface.dropTable('users');
  },
};
  • 执行 migrate 进行数据库变更
# 升级数据库
npx sequelize db:migrate
# 如果有问题需要回滚,可以通过 `db:migrate:undo` 回退一个变更
# npx sequelize db:migrate:undo
# 可以通过 `db:migrate:undo:all` 回退到初始状态
# npx sequelize db:migrate:undo:all

三、编写模型

  • 现在终于可以开始编写代码实现业务逻辑了,首先我们来在 app/model/ 目录下编写 user 这个 Model:
'use strict';

module.exports = app => {
  const { STRING, INTEGER, DATE } = app.Sequelize;

  const User = app.model.define('user', {
    id: { type: INTEGER, primaryKey: true, autoIncrement: true },
    name: STRING(30),
    age: INTEGER,
    created_at: DATE,
    updated_at: DATE,
  });

  return User;
};

四、编写业务逻辑增删改查接口

  • 这个 Model 就可以在 Controller 和 Service 中通过 app.model.User 或者 ctx.model.User 访问到了,例如我们编写 app/controller/users.js:
'use strict';
const Controller = require('egg').Controller;
const Sequelize = require('sequelize');

class ScenicController extends Controller {
  async detail() {
    const params = this.ctx.params;
    const scenics = await this.ctx.model.Scenic.findByPk(params.id);
    const image = scenics.picture.split(',');
    scenics.picture = image;
    this.ctx.body = scenics;
  }
  async list() {
    const Op = Sequelize.Op;
    const query = this.ctx.query;
    const area = query.area;
    const type = query.type;
    const page = Number(query.page) || 1;
    const pagesize = Number(query.pagesize) || 10;
    const fifter = {};
    if (type) {
      fifter.type = {
        [Op.like]: '%' + type + '%',
      };
    }
    if (area) {
      fifter.area = {
        [Op.like]: '%' + area + '%',
      };
    }
    console.log(query);
    const scenics = await this.ctx.model.Scenic.findAndCountAll({
      attributes: { exclude: [ 'picture', 'audio' ] },
      where: fifter,
      offset: (page - 1) * pagesize,
      limit: pagesize,
    });
    this.ctx.body = scenics;
  }
  async destroy() {
    const params = this.ctx.params;
    const leavemessage = await this.ctx.model.Leavemessage.findByPk(params.id);
    if (!leavemessage) {
      this.ctx.body = {
        status: 401,
        error: 'id不存在',
      };
      return;
    }
    await leavemessage.destroy();
    this.ctx.body = {
      code: '200',
      message: '删除成功',
    };
  }
  async create() {
    const leavemessage = await this.ctx.model.Leavemessage.create(this.ctx.request.body);
    if (!leavemessage) {
      this.ctx.body = {
        status: 401,
        error: '请输入正确的参数',
      };
      return;
    }
    this.ctx.body = {
      code: 200,
      data: leavemessage,
    };
  }
  async edit() {
    const leavemessage = await this.ctx.model.Leavemessage.findByPk(this.ctx.params.id);
    if (!leavemessage) {
      this.ctx.body = {
        status: 401,
        error: 'id不存在',
      };
      return;
    }
    await leavemessage.update(this.ctx.request.body);
    this.ctx.body = {
      code: 200,
      data: leavemessage,
    };
  }
}

module.exports = ScenicController;

五、编写路由

  • 最后我们将这个 controller 挂载到路由上:
'use strict';

/**
 * @param {Egg.Application} app - egg application
 */
module.exports = app => {
  const { router, controller } = app;
  router.get('/api/users/', controller.user.list);// 用户列表
  router.get('/api/scenics/', controller.scenic.list); // 景点列表
  router.get('/api/leavmessages/', controller.leavemessage.list); // 留言列表
  router.get('/api/scenic/:id', controller.scenic.detail); // 景点详情
  router.get('/api/admin/leavemessages/', controller.admin.leavemessagelist); // 后台管理景点列表
  router.get('/api/admin/scenics/', controller.admin.sceniclist); // 后台管理留言列表
  router.post('/api/leavemessage/', controller.admin.create); // 后台管理增加留言
  router.put('/api/leavemessage/:id', controller.admin.edit); // 后台管理修改留言
  router.delete('/api/leavemessage/:id', controller.admin.destroy); // 后台管理删除留言
  router.post('/api/scenic/', controller.admin.sceniccreate); // 后台管理增加景点
  router.put('/api/scenic/:id', controller.admin.scenicedit); // 后台管理修改景点
  router.delete('/api/scenic/:id', controller.admin.scenicdestroy); // 后台管理删除景点
};

  • 针对 users 表的 CURD 操作的接口就开发完了

六、egg-validate字段验证模块

安装

cnpm i egg-validate --save

配置项目

// config/plugin.js
exports.validate = {
  enable: true,
  package: 'egg-validate',
};
// config/config.default.js
exports.validate = {
  convert: false,
  // validateRoot: false,
};

使用

const rule = {
      content: { type: 'string' },
    };
    this.ctx.validate(rule);

七、定时任务

  • 所有的定时任务都统一存放在 app/schedule 目录下,每一个文件都是一个独立的定时任务,可以配置定时任务的属性和要执行的方法。

  • 一个简单的例子,我们定义一个更新远程数据到内存缓存的定时任务,就可以在 app/schedule 目录下创建一个 update_cache.js 文件


'use strict';
const Subscription = require('egg').Subscription;

class getInfo extends Subscription {
  static get schedule() {
    return {
      // interval: 3000,
      // 每三小时准点执行一次
      cron: '0 0 */1 * * *',
      type: 'worker',
    };
  }
  async subscribe() {
    const info = this.ctx.curl('https://hsyj.shikehuyu.com/api/scenics/',
      {
        dataType: 'json',
      });
    console.log((await info).data);
  }
}


module.exports = getInfo;
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值