一 、创建项目:
1、使用egg.js框架提供的脚手架搭建:
npm i -g egg-init
egg-init egg-demo --type=simple //--type=simple可以去掉然后自己配置
cd egg-demo
npm i
2、启动项目:
npm run dev
浏览器打开:localhost:7001
二、项目配置
1、Controller
#使用场景
编写 Controller
我们约定把 Controller 放置在 app/controller 目录下:
// app/controller/user.js
const { Controller } = require('egg');
class UserController extends Controller {
async create() {
const { ctx, service } = this;
// 获取请求信息
const userInfo = ctx.request.body;
// 校验参数
ctx.assert(userInfo && userInfo.name, 422, 'user name is required.');
// 调用 Service 进行业务处理
const result = await service.user.create(userInfo);
// 响应内容和响应码
ctx.body = result;
ctx.status = 201;
}
}
module.exports = UserController;
然后通过路由配置 URL 请求映射:
// app/router.js
module.exports = app => {
const { router, controller } = app;
router.post('/api/user', controller.user.create);
};
然后通过 POST /api/user 即可访问
2、Service
#使用场景
编写 Service
我们约定把 Service 放置在 app/service 目录下:
// app/service/user.js
const { Service } = require('egg');
class UserService extends Service {
async find(uid) {
const user = await this.ctx.db.query('select * from user where uid = ?', uid);
return user;
}
}
module.exports = UserService;
使用 Service
框架会默认挂载到 ctx.service 上,对应的 Key 为文件名的驼峰格式。
如上面的 Service 会挂载为 ctx.service.user。
然后就可以在 Controller 里调用:
// app/controller/user.js
const { Controller } = require('egg');
class UserController extends Controller {
async info() {
const { ctx } = this;
const userId = ctx.params.id;
const userInfo = await ctx.service.user.find(userId);
ctx.body = userInfo;
}
}
module.exports = UserController;
3、Router
#使用场景
编写路由
我们约定 app/router.js 文件用于统一所有路由规则。
通过统一的配置,可以避免路由规则逻辑散落在多个地方,从而出现未知的冲突,可以更方便的来查看全局的路由规则。
假设有以下 Controller 定义:
// app/controller/user.js
class UserController extends Controller {
async info() {
const { ctx } = this;
ctx.body = {
name: `hello ${ctx.params.id}`,
};
}
}
则我们可以定义对应的路由如下:
// app/router.js
module.exports = app => {
const { router, controller } = app;
// GET /user/123
router.get('/user/:id', controller.user.info);
};
路由路径
即为上面的 /some-path,并支持命名参数。
// app/router.js
module.exports = app => {
const { router, controller } = app;
router.get('/home', controller.home.index);
// 支持命名参数,通过 `ctx.params.id` 可以取出。
router.get('/user/:id', controller.user.detail);
};
也支持正则式:
// app/router.js
module.exports = app => {
const { router, controller } = app;
// 可以通过 ctx.params[0]
获取到对应的正则分组信息。
router.get(/^\/package\/([\w-.]+\/[\w-.]+)$/, controller.package.detail);
};
如果你有一个通配的路由映射,需注意顺序,放在后面,如:
router.get('/user/manager', controller.user.manager);
router.get('/user/:id', controller.user.detail);
4、Middleware
#使用场景
编写中间件
我们约定把中间件放置在 app/middleware 目录下:
// app/middleware/response_time.js
module.exports = () => {
return async function responseTime(ctx, next) {
const start = Date.now();
await next();
const cost = Date.now() - start;
ctx.set('X-Response-Time', `${cost}ms`);
}
};
5、连接数据库
sequelize数据库配置
- 安装并配置egg-sequelize插件(它会辅助我们将定义好的 Model 对象加载到 app 和 ctx 上)和mysql2模块:
npm install --save egg-sequelize mysql2
- 在
config/plugin.js
中引入 egg-sequelize 插件
exports.sequelize = {
enable: true,
package: 'egg-sequelize',
};
- 在
config/config.default.js
config.sequelize = {
dialect: 'mysql',
host: '127.0.0.1',
username: "root",
password: 'root',
port: 3306,
database: 'egg-clouddisk',
// 中国时区
timezone: '+08:00',
define: {
// 取消数据表名复数
freezeTableName: true,
// 自动写入时间戳 created_at updated_at
timestamps: true,
// 字段生成软删除时间戳 deleted_at
// paranoid: true,
createdAt: 'created_time',
updatedAt: 'updated_time',
// deletedAt: 'deleted_time',
// 所有驼峰命名格式化
underscored: true
}
};
数据库迁移配置
- sequelize 提供了sequelize-cli工具来实现Migrations,我们也可以在 egg 项目中引入 sequelize-cli。
npm 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
// npx sequelize init:models
- 行完后会生成
database/config.json
文件和database/migrations
目录,我们修改一下database/config.json
中的内容,将其改成我们项目中使用的数据库配置:
{
"development": {
"username": "root",
"password": null,
"database": "egg-clouddisk",
"host": "127.0.0.1",
"dialect": "mysql",
"timezone": "+08:00"
}
}
5.创建数据库
npx sequelize db:create
# 升级数据库
npx sequelize db:migrate
# 如果有问题需要回滚,可以通过 `db:migrate:undo` 回退一个变更
# npx sequelize db:migrate:undo
# 可以通过 `db:migrate:undo:all` 回退到初始状态
# npx sequelize db:migrate:undo:all
创建数据迁移表
npx sequelize migration:generate --name=user
1.执行完命令后,会在database / migrations / 目录下生成数据表迁移文件,然后定义
'**use strict';
module.exports = {
up:** (queryInterface, Sequelize) => {
const { INTEGER, STRING, DATE, ENUM, TEXT } = Sequelize;
return queryInterface.createTable('user', {
id: {
type: INTEGER(20),
primaryKey: true,
autoIncrement: true
},
username: {
type: STRING(30),
allowNull: false,
defaultValue: '',
comment: '用户名',
unique: true
},
nickname: {
type: STRING(30),
allowNull: false,
defaultValue: '',
comment: '昵称',
},
email: {
type: STRING(160),
allowNull: false,
defaultValue: '',
comment: '邮箱'
},
password: {
type: STRING,
allowNull: false,
defaultValue: '',
comment: "密码"
},
avatar: {
type: STRING,
allowNull: true,
defaultValue: '',
comment: '头像'
},
phone: {
type: STRING(11),
allowNull: false,
defaultValue: '',
comment: '手机'
},
sex: {
type: ENUM,
values: ["男", '女', '保密'],
allowNull: false,
defaultValue: '男',
comment: '性别'
},
desc: {
type: TEXT,
allowNull: false,
defaultValue: '',
comment: '个性签名',
},
total_size: {
type: INTEGER,
defaultValue: 0,
comment: '网盘总大小,单位:kb',
},
used_size: {
type: INTEGER,
defaultValue: 0,
comment: '网盘已使用大小,单位:kb',
},
created_time: DATE,
updated_time: DATE,
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('user');
}
};
- 执行 migrate 进行数据库变更
npx sequelize db:migrate
模型创建
在app创建model文件夹,创建user文件,文件必须跟数据表名一样
定义
// app/model/user.js
const crypto = require('crypto');
module.exports = app => {
const { STRING, INTEGER, DATE, ENUM, TEXT } = app.Sequelize;
const User = app.model.define('user', {
id: {
type: INTEGER(20),
primaryKey: true,
autoIncrement: true
},
username: {
type: STRING(30),
allowNull: false,
defaultValue: '',
comment: '用户名',
unique: true
},
nickname: {
type: STRING(30),
allowNull: false,
defaultValue: '',
comment: '昵称',
},
email: {
type: STRING(160),
allowNull: false,
defaultValue: '',
comment: '邮箱'
},
password: {
type: STRING,
allowNull: false,
defaultValue: '',
comment: "密码",
set(val) {
const hmac = crypto.createHash("sha256", app.config.crypto.secret);
hmac.update(val);
let hash = hmac.digest("hex");
this.setDataValue('password', hash);
}
},
avatar: {
type: STRING,
allowNull: true,
defaultValue: '',
comment: '头像'
},
phone: {
type: STRING(11),
allowNull: false,
defaultValue: '',
comment: '手机'
},
sex: {
type: ENUM,
values: ["男", '女', '保密'],
allowNull: false,
defaultValue: '男',
comment: '性别'
},
desc: {
type: TEXT,
allowNull: false,
defaultValue: '',
comment: '个性签名',
},
total_size: {
type: INTEGER,
defaultValue: 10485760,
comment: '网盘总大小,单位:kb',
},
used_size: {
type: INTEGER,
defaultValue: 0,
comment: '网盘已使用大小,单位:kb',
},
created_time: DATE,
updated_time: DATE,
});
// User.associate = function (models) {
// // 关联文件
// User.hasMany(app.model.File);
// }
return User;
};