js date转string_egg.js 快速入门

    Egg的主要特点是:奉行『约定优于配置』,按照一套统一的约定进行应用开发。

    Egg 在 Koa 的基础上进行增强最重要的就是基于一定的约定,根据功能差异将代码放到不同的目录下管理。也就是说,目录和文件一定要按照规定来,不能自己随心所欲地设定。

    但是,很多设定官方文档没有阐述得很详细,遇到问题的时候,需要去网上搜索,或者github上下载源码看。

    Loader 实现了这套约定,并抽象了很多底层 API 可以进一步扩展。

    具体见官网的说明:

https://eggjs.org/zh-cn/advanced/loader.html

    官网上,可以找到比较基础的说明。我觉得,如果想快速入门:

    (1) 可以先写一个Demo,知道怎么跑起来的

    (2) 直接跟项目,着手解决项目问题。

▪ 快速初始化


  • 我们推荐直接使用脚手架,只需几条简单指令,即可快速生成项目(npm >=6.1.0):

> mkdir egg-example && cd egg-example> npm init egg --type=simple> npm i

  • 启动项目:

> npm run dev

▪ 简易项目


    目的:从Mysql获取数据,对外提供restful服务

37831055b3d2a144a4a7c735a8e8fb75.png

    • 通过 npm 初始化一个项目

> mkdir egg-demo && cd egg-demo> npm init egg> npm i

  • 安装egg-sequelize

    用来操作mysql数据库

> npm install --save egg-sequelize mysql2

  • 在 config/plugin.js 中引入 egg-sequelize 插件

exports.sequelize = {
  enable: true,package: 'egg-sequelize',
};exports.security = {
    enable: false
}

  • 在 config/config.default.js 中编写 sequelize 配置

    当然,DEV,PRD环境的数据库连接不同,可以不写在config.default.js中,开发时写在config.local.js,测试时写在config.unittest.js,prd写在config.prod.js。

config.sequelize = {
    dialect: 'mysql', // support: mysql, mariadb, postgres, mssql
    database: 'demo',
    host: '192.168.xxx.xx',
    port: 3306,
    username: 'xxx',
    password: 'xxx',
  };

  • 编写 Model

    即与数据库关联的类,app/model/user.js。

module.exports = app => {const { STRING, INTEGER, DATE } = app.Sequelize;const User = app.model.define('users', {
    id: { type: INTEGER, primaryKey: true, autoIncrement: true },
    name: STRING(30),
    age: INTEGER,
    createdAt: DATE,
    updatedAt: DATE,
  });return User;
};

  • 编写 Controller

    即CRUD的数据访问,app/controller/users.js

const Controller = require('egg').Controller;function toInt(str) {if (typeof str === 'number') return str;if (!str) return str;return parseInt(str, 10) || 0;
}class UserController extends Controller {async index() {const ctx = this.ctx;const query = { limit: toInt(ctx.query.limit), offset: toInt(ctx.query.offset) };
    ctx.body = await ctx.model.User.findAll(query);
  }async show() {const ctx = this.ctx;
    ctx.body = await ctx.model.User.findByPk(toInt(ctx.params.id));
  }async create() {const ctx = this.ctx;const { name, age } = ctx.request.body;const user = await ctx.model.User.create({ name, age });
    ctx.status = 201;
    ctx.body = user;
  }async update() {const ctx = this.ctx;const id = toInt(ctx.params.id);const user = await ctx.model.User.findByPk(id);if (!user) {
      ctx.status = 404;return;
    }const { name, age } = ctx.request.body;await user.update({ name, age });
    ctx.body = user;
  }async destroy() {const ctx = this.ctx;const id = toInt(ctx.params.id);const user = await ctx.model.User.findByPk(id);if (!user) {
      ctx.status = 404;return;
    }await user.destroy();
    ctx.status = 200;
  }
}
module.exports = UserController;

  • 编写 router

    即给外部调用的restful接口,app/router.js。

module.exports = app => {const { router, controller } = app;
  router.get('/', controller.home.index);
  router.resources('user', '/user', controller.user);
};

    controller.home.index即访问controller目录下的home.js文件,里面的index()方法。

757bebfcf1c7a24a1e685b41016f21fc.png

    这里的resources有点特殊,包括CRUD。

103f642d1968364e9f7f4686aa8b2873.png

  • 创建数据库

CREATE TABLE `users` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'primary key',`name` varchar(30) DEFAULT NULL COMMENT 'user name',`age` int(11) DEFAULT NULL COMMENT 'user age',`created_at` datetime DEFAULT NULL COMMENT 'created time',`updated_at` datetime DEFAULT NULL COMMENT 'updated time',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='user';

  • 插入数据

INSERT INTO users (id, name, age, created_at, updated_at) VALUES
(1, '张三', 18, '2020-10-21 23:29:39', '2020-10-21 23:29:39'),
(2, '李四', 19, '2020-10-21 23:29:39', '2020-10-21 23:29:39');

   · 通过以上的设定,整个项目就完成了,运行:

> npm run dev

   · postman 访问

get http://127.0.0.1:7001/user?limit=5&offset=2

▪ 实际项目


  以下是一个项目的结构,主要通过查询mysql数据,对外提供restful服务。  

effe1345ffcab701b65fc1a12faf40b6.png

  • 配置文件

    · dev 环境加载一个配置的加载顺序如下,后加载的会覆盖前面的同名配置。

   -> config.default.js

   -> config.local.js

    另外,config.local.js 中可以引入 config.mysql.js

const sequelizeConfig = require('./config.mysql')

75fe22dc163c1e0c26ed20334a29941c.png

   · prod 环境加载一个配置的加载顺序如下。

   -> config.default.js

   -> config.prod.js

  • 插件

   · 例如:开启egg-sequelize,实现对mysql的操作

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

   · 例如:开启egg-redis 插件

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

  • Router (路由)

   主要用来描述请求 URL 和具体承担执行动作的 Controller 的对应关系, 框架约定了 app/router.js 文件用于统一所有路由规则。

6d8f90dd079062974e9caffb5750523b.png

  • 控制器(Controller)

    我们通过 Router 将用户的请求基于 method 和 URL 分发到了对应的 Controller 上,负责解析用户的输入,处理后返回相应的结果:

    (1) 获取用户通过 HTTP 传递过来的请求参数。

    (2) 校验、组装参数。

    (3) 调用 Service 进行业务处理,必要时处理转换 Service 的返回结果,让它适应用户的需求。

    (4) 通过 HTTP 将结果响应给用户。

80c51f2be0e1dd6ddbc17f82b83fcec7.png

  • 服务(Service)

    简单来说,Service 就是在复杂业务场景下用于做业务逻辑封装的一个抽象层,提供这个抽象有以下几个好处:

    (1) 保持 Controller 中的逻辑更加简洁。

    (2) 保持业务逻辑的独立性,抽象出来的 Service 可以被多个 Controller 重复调用。

    (3) 将逻辑和展现分离,更容易编写测试用例,测试用例的编写具体可以查看这里。

c6c8b696ce0dd365c5e651cc32f2c2f5.png

    可以看到,SQL一般都在service中书写。

  • 中间件(Middleware)

    Egg 的中间件形式和 Koa 的中间件形式是一样的,都是基于洋葱圈模型。每次我们编写一个中间件,就相当于在洋葱外面包了一层。

    例如:指定只有当 body 大于配置的 threshold 时才进行 gzip 压缩,我们要在 app/middleware 目录下新建一个文件 gzip.js,

     // app/middleware/gzip.js

const isJSON = require('koa-is-json');const zlib = require('zlib');module.exports = options => {return async function gzip(ctx, next) {await next();// 后续中间件执行完成后将响应体转换成 gziplet body = ctx.body;if (!body) return;// 支持 options.thresholdif (options.threshold && ctx.length < options.threshold) return;if (isJSON(body)) body = JSON.stringify(body);// 设置 gzip body,修正响应头const stream = zlib.createGzip();
    stream.end(body);
    ctx.body = stream;
    ctx.set('Content-Encoding', 'gzip');
  };
};

   · 全局使用中间件

    中间件编写完成后,我们还需要手动挂载,在应用中使用中间件,需要加载上面的 gzip 中间件,在 config.default.js 中加入下面的配置就完成了中间件的开启和配置:

module.exports = {// 配置需要的中间件,数组顺序即为中间件的加载顺序
  middleware: [ 'gzip' ],// 配置 gzip 中间件的配置
  gzip: {
    threshold: 1024, // 小于 1k 的响应体不压缩
  },
};

   · router 中使用中间件

    以上方式配置的中间件是全局的,会处理每一次请求。如果你只想针对单个路由生效,可以直接在 app/router.js 中实例化和挂载,如下:

module.exports = app => {const gzip = app.middleware.gzip({ threshold: 1024 });
  app.router.get('/needgzip', gzip, app.controller.handler);
};

  • 定时任务

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

    定时任务可以指定 interval 或者 cron 两种不同的定时方式。

   · interval

    通过 schedule.interval 参数来配置定时任务的执行时机,定时任务将会每间隔指定的时间执行一次。

module.exports = {
  schedule: {// 每 10 秒执行一次
    interval: '10s',
  },
};

   · cron

   通过 schedule.cron 参数来配置定时任务的执行时机,定时任务将会按照 cron 表达式在特定的时间点执行。

module.exports = {
  schedule: {// 每三小时准点执行一次
    cron: '0 0 */3 * * *',
  },
};
* * * * * *
┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ |
│ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
│ │ │ │ └───── month (1 - 12)
│ │ │ └────────── day of month (1 - 31)
│ │ └─────────────── hour (0 - 23)
│ └──────────────────── minute (0 - 59)
└───────────────────────── second (0 - 59, optional)

    如上所述,egg.js的大概开发流程就是这样,比较简单,效率的较高,具体的操作,大家可找官网的资料,或者github上的案例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值