项目初始化
1 2 3
| npm init egg --type=simple npm i npm run dev
|
项目预览
1 2 3 4 5 6 7 8
| egg-example ├── app │ ├── controller │ │ └── home.js │ └── router.js ├── config │ └── config.default.js └── package.json
|
更改端口
在config.default .js下面添加下面的代码
1 2 3 4 5 6 7
| config.cluster = { listen: { path: '', port: 8000, hostname: '127.0.0.1', } };
|
跨域
出现post请求会报错
- 在 config/plugin.js 文件中添加以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| 'use strict';
module.exports = { cors: { enable: true, package: 'egg-cors' } };
|
在 config/config.default.js 中添加以下代码,自此通过外部访问的 post 请求就可以正常访问了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
'use strict';
module.exports = appInfo => {
const config = exports = {};
const userConfig = { }; config.security = { csrf: { enable: false, }, domainWhiteList: [] }
config.cors = { origin: "*", allowMethods: 'GET, PUT, POST, DELETE, PATCH' }
return { ...config, ...userConfig, }; };
|
mysql
在配置文件里面配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
'use strict';
module.exports = appInfo => {
const config = exports = {};
const userConfig = { }; config.security = { csrf: { enable: false, }, domainWhiteList: [] }
config.cors = { origin: "*", allowMethods: 'GET, PUT, POST, DELETE, PATCH' } config.mysql = { client: { host: 'localhost', port: '3306', user: 'root', password: '196691', database: 'books', }, app: true, agent: false, };
return { ...config, ...userConfig, }; };
|
在plugin.js插件里面配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 'use strict';
module.exports = { cors: { enable: true, package: 'egg-cors' }, mysql: { enable: true, package: 'egg-mysql', } };
|
模糊查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| async getpage() { const { ctx, app } = this const params = ctx.request.query console.log(params); let sql = 'select * from user' let content = []; let isMore = false; if (params.username) { sql += " where username like ?"; content.push("%" + params.username + "%"); isMore = true; } if (params.age) { if (isMore) { sql += "and age LIKE ?"; } else { sql += " WHERE age LIKE ?"; } content.push("%" + params.age + "%") isMore = true;
} if (params.pageIndex || params.pageSize) { let current = params.pageIndex; let pageSize = params.pageSize; sql += " limit ?,?"; content.push((current - 1) * pageSize, parseInt(pageSize)); } const res = await app.mysql.query(sql, content) return success('查询分页成功', res)
}
|
请求参数
- 路径参数:params
- 查询参数:query
- 表单参数:request.body
- json参数:request.body
路径传参
ctx.params
查询传参
ctx.query
表单参数
用ctx.request.body
json参数
和表单参数一样
封装结果集
新建util 文件,然后新建utils文件夹
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| function success(msg) { return { code: 200, msg: msg,
} }
function success(msg, data) { return { code: 200, msg: msg, data } } function error(msg) { return { code: 500, msg: msg, } } function error(msg, data) { return { code: 500, msg: msg, data } } module.exports = { success, error }
|
图书增删改查
查询单个:get,select
添加:insert
修改:update
删除:delete
路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 'use strict';
module.exports = app => { const { router, controller } = app; router.get('/getall', controller.book.getAll) router.get('/get', controller.book.get) router.post('/add', controller.book.add) router.put('/update', controller.book.update) router.delete('/delete', controller.book.delete) };
|
controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| const { Controller } = require('egg')
class BookController extends Controller { async getAll() { const { ctx } = this; ctx.body = await ctx.service.book.getAll(); } async get() { const { ctx } = this; ctx.body = await ctx.service.book.get(); } async add() { const { ctx } = this ctx.body = await ctx.service.book.add() } async update() { const { ctx } = this ctx.body = await ctx.service.book.update() } async delete() { const { ctx } = this ctx.body = await ctx.service.book.delete() } }
module.exports = BookController
|
service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| const { Service } = require('egg') const { success, error } = require('../util/utils')
class BookService extends Service { async getAll() { const { ctx, app } = this try { const res = await app.mysql.select('article') return success('查询所有成功', res) } catch { return error('查询所有失败') }
} async get() { const { ctx, app } = this const body = ctx.request.body try { const res = await app.mysql.get('article', body) return success("查询单个成功", res) } catch { return error('查询单个失败') } } async add() { const { ctx, app } = this const body = ctx.request.body const res = await app.mysql.insert('article', body)
if (res.affectedRows == 1) { return success('插入成功') } else { return error('插入失败') } } async update() { const { ctx, app } = this const body = ctx.request.body const res = await app.mysql.update('article', body)
if (res.affectedRows == 1) { return success('修改成功') } else { return error('修改失败') } } async delete() { const { ctx, app } = this const body = ctx.request.body const res = await app.mysql.delete('article', body)
if (res.affectedRows == 1) { return success('删除成功') } else { return error('删除失败') } }
}
module.exports = BookService;
|
多表联查
jwt
安装
配置plugin.js
1 2 3 4
| jwt: { enable: true, package: 'egg-jwt', },
|
配置config.js
1 2 3 4 5 6 7
| config.jwt = { secret: 'zouwen', sign: { expiresIn: 8 * (60 * 60) } };
|
生成token
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| async login() { const { ctx, app } = this const body = ctx.request.body let { username } = body const res = await app.mysql.get('user', { username: username }) if (res) { if (body.password == res.password) { const token = app.jwt.sign({username:username},app.config.jwt.secret) return success("登录成功", token) } else { return error('登录失败!密码错误') } } else { return error('该用户未注册') }
}
|
解析token
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| async getinfo() { const { ctx, app } = this const body = ctx.request.body let token = ctx.request.header.authorization token = token.split(' ')[1] const username = ctx.app.jwt.verify(token, ctx.app.jwt.secret).username try { const res = await app.mysql.get('user', { username: username }) return success('获取用户详情成功', res) } catch { return success('获取用户详情失败') }
}
|
jwt中间件
新建middleware文件夹,然后新建jwt.js文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
const whiteList = ['user/login', 'user/register']
module.exports = (options) => { return async function (ctx, next) { const isInWhiteList = whiteList.some(item => item == ctx.request.url) if (!isInWhiteList) { const token = ctx.request.header.authorization
if (token) { const secret = ctx.app.config.jwt.secret const decoded = ctx.app.jwt.verify(token.split(' ')[1], secret) || 'false' if (decoded !== 'false') { await next() } else { ctx.throw(403, '无效Token') } } else { ctx.throw(403, '无Token') } } else { await next() } } }
|
route.js引入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 'use strict';
module.exports = app => { const { router, controller, middleware } = app; const jwt = middleware.jwt(app.config.jwt);
router.post('/user/register', controller.user.register) router.post('/user/login', controller.user.login) router.get('/user/getinfo', jwt, controller.user.getinfo) router.post('/user/getpage', jwt, controller.user.getpage) router.put('/user/update', jwt, controller.user.update) router.delete('/user/delete', jwt, controller.user.delete) };
|
全局异常
在middleware下面新建error_handler.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| module.exports = () => { return async function errorHandler(ctx, next) { try { await next(); } catch (err) { ctx.app.emit('error 全局异常捕获', err, ctx);
const status = err.status || 500; const error = status === 500 && ctx.app.config.env === 'prod' ? 'Internal Server Error' : err.message;
ctx.body = { error: '捕获到全局异常' ,data:err.message}; if (status === 422) { ctx.body.detail = err.errors; } ctx.status = status; } }; };
|
在config.default.js配置
1 2 3 4 5
| config.middleware = ['errorHandler']; config.errorHandler = { match: '/api', };
|
上传头像
在config配置里面配置
1 2 3
| config.multipart = { mode:'file' };
|
在public文件夹下面新建一个upload文件夹
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| const {Controller} = require('egg') const fs = require('fs'); const path = require('path'); const moment = require('moment'); const mkdirp = require('mkdirp'); class uploadController extends Controller{
async uploads(){ const { ctx, app } = this; let userId = ctx.params.id console.log('id:',userId); const file = ctx.request.files[0] const toFileName = '/public/upload/' + file.filename; const to = path.dirname(__dirname) + toFileName;
await fs.copyFileSync(file.filepath, to) const newUrl = "http://127.0.0.1:7001" + toFileName;
const results = await app.mysql.query('update userinfo set pic = ? where id = ?', [newUrl, userId]); ctx.body = { msg: '图片上传成功', url: newUrl }
} }
module.exports = uploadController
|
深入了解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| egg-project ├── package.json ├── app.js (可选) ├── agent.js (可选) ├── app | ├── router.js │ ├── controller │ | └── home.js │ ├── service (可选) │ | └── user.js │ ├── middleware (可选) │ | └── response_time.js │ ├── schedule (可选) │ | └── my_task.js │ ├── public (可选) │ | └── reset.css │ ├── view (可选) │ | └── home.tpl │ └── extend (可选) │ ├── helper.js (可选) │ ├── request.js (可选) │ ├── response.js (可选) │ ├── context.js (可选) │ ├── application.js (可选) │ └── agent.js (可选) ├── config | ├── plugin.js | ├── config.default.js │ ├── config.prod.js | ├── config.test.js (可选) | ├── config.local.js (可选) | └── config.unittest.js (可选) └── test ├── middleware | └── response_time.test.js └── controller └── home.test.js
|
框架内置基础对象:
4个继承Koa而来的对象:app,ctx,Response,Request
框架自身拓展的:Controller,Service,Helper,Connfig,Logger
Application
Application 是全局应用对象。它继承自 Koa.Application,在它上面我们可以挂载一些全局的方法和对象。我们可以轻松的在插件或者应用中扩展 Application 对象。
sequelize
配置
1
| npm install --save egg-sequelize mysql2
|
在plugin.js引入插件
1 2 3 4
| sequelize: { enable: true, package: 'egg-sequelize', }
|
在config.default.js里面配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| config.sequelize = { dialect: 'mysql', host: 'localhost', port: 3306, database: 'sequelize', username: 'root', password: '196691', timezone: '+08:00', define: { timestamps: true, paranoid: true, freezeTableName: true, underscored: false }, logging: true, dialectOptions: { dateStrings: true, typeCast: true } };
|
1.默认情况下查询的日期是这种样子2022-01-02T09:14:03.102Z,我们需要对它自动格式化才行。
1 2 3 4
| dialectOptions: { dateStrings: true, typeCast: true }
|
这样就会格式化成酱紫:2022-01-04 10:39:56
2.quelize会将Parents默认转变为复数,也就是直接加s变为Parentss,很多时候这并不是我们想要的,可以对其进行修改。
1 2 3
| "define": { "freezeTableName": true }
|
在app目录下面新建model文件夹,然后建立book.js文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| module.exports = app => { const { STRING, INTEGER } = app.Sequelize;
const Book = app.model.define('book', { id: { type: INTEGER, autoIncrement: true, primaryKey: true }, name: { type: STRING, allowNull: true, }, title: { type: STRING, allowNull: true }, author: { type: STRING, allowNull: true } });
return Book; }
|
service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| const { Service } = require('egg') const { success, error } = require('../util/utils')
class BookService extends Service { async getbook() { const { ctx, app } = this const res = await ctx.model.Book.findAll() return res } async addbook() { const { ctx, app } = this const res = await ctx.model.Book.create({ name: 'test', title: '这是test新增测试', author: 'zouwen333' }) return res } async updatebook() { const { ctx, app } = this const effected = await ctx.model.Book.update({ id: 7, name: 'zo',
}, { where: { id: 6 } }) if (effected === 1) { return `修改成功` } } async deletebook() { const { ctx, app } = this const effected = await ctx.model.Book.destroy({ where: { id: 7 } }) if (effected === 1) { return `删除成功` } }
}
module.exports = BookService;
|
controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| const { Controller } = require('egg')
class BookController extends Controller { async getbook() { const { ctx } = this; ctx.body = await ctx.service.book.getbook() } async addbook() { const { ctx } = this; ctx.body = await ctx.service.book.addbook() } async updatebook() { const { ctx } = this; ctx.body = await ctx.service.book.updatebook() } async deletebook() { const { ctx } = this; ctx.body = await ctx.service.book.deletebook() } }
module.exports = BookController
|
路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| 'use strict';
module.exports = app => { const { router, controller, middleware } = app; const jwt = middleware.jwt(app.config.jwt);
router.post('/api/user/register', controller.user.register) router.post('/api/user/login', controller.user.login) router.get('/api/user/getinfo', jwt, controller.user.getinfo) router.post('/api/user/getpage', jwt, controller.user.getpage) router.put('/api/user/update', jwt, controller.user.update) router.delete('/api/user/delete', jwt, controller.user.delete)
router.get('/getbook', controller.book.getbook) router.post('/addbook', controller.book.addbook) router.put('/updatebook', controller.book.updatebook) router.delete('/deletebook', controller.book.deletebook)
router.get('/student', controller.student.getall) };
|