目录
一. egg的基本了解
1. egg.js是
为企业级框架和应用而生,帮助开发人员和开发团队降低开发和维护成本。egg的继承于koa的内置对象有(request,response,application,context),加上扩展的一些对象如(controller,service,helper,config,logger)
2. egg设计原则
- egg提供web开发的核心功能和一套灵活可扩展的插件机制( 通过egg, 团队的架构师和技术负责人可以非常容易基于自身的技术架构在egg基础上扩展出适合自身业务场景的框架)。
- egg的插件机制有很高的可扩展性,一个插件只做一件事,比如:
nunjucks模板 —— egg-view-nunjucks
mysql数据库 —— egg-mysql
- egg奉行约定优于配置,按照一套统一的约定进行应用开发,(缺少约定的框架会因为标准的mvc模型而千奇百怪的写法)
3. egg快速入门
- 快速初始化
$ mkdir egg-example && cd egg-example
$ npm init egg --type=simple (取名字,写描述,默认安全字符串)
$ npm i (安装依赖)
$ npm run dev (启动项目)
$ open http://localhost:7001
二. egg基本功能
1.控制器( Controller)
我们通过Router将用户的请求基于method和url分发到了对应的Controller上, Controller的作用是负责解析用户的输入,处理后返回响应的结果,例如,
- 在 RESTful 接口中,Controller 接受用户的参数,从数据库中查找内容返回给用户或者将用户的请求更新到数据库中。
- 在 HTML 页面请求中,Controller 根据用户访问不同的 URL,渲染不同的模板得到 HTML 返回给用户。
- 在代理服务器中,Controller 将用户的请求转发到其他服务器上,并将其他服务器的处理结果返回给用户。
在控制器中使用class和async编写相关代码,然后exports导出,在app/router.js文件中进行路由的映射
get请求示例:
//controller.js文件
'use strict';
const Controller = require('egg').Controller;
class jspangController extends Controller {
async index() {
const { ctx } = this;
ctx.body = '<h1> you are jspang</h1>';
}
async getGirl() {
const { ctx } = this;
await new Promise(resolve => {
setTimeout(() => {
resolve(ctx.body = '<h1>小红,正在向你走俩</h1>');
}, 1000);
});
}
// 自由传参模式
async getGirls() {
const ctx = this.ctx;
ctx.body = ctx.query;
}
// 严格传参模式
async getGirls1() {
const ctx = this.ctx;
ctx.body = "getgirls"+ctx.params.name;
}
}
// 将其暴露出去
module.exports = jspangController;
// router.js文件
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.get('/jspang', controller.jspang.index);
router.get('/getGirl', controller.jspang.getGirl);
router.get('/getGirls', controller.jspang.getGirls);
router.get('/getGirls1/:name', controller.jspang.getGirls1);
};
post请求示例:
async add() {
const ctx = this;
ctx.body = {
status: 200,
data:ctx.request.body
}
}
egg.js的单元测试编写(用脚手架搭建的项目有示例单元测试)
'use strict';
const { app, assert } = require('egg-mock/bootstrap');
describe('test/app/controller/jspang.test.js', () => {
it('should assert', () => {
const pkg = require('../../../package.json');
assert(app.config.keys.startsWith(pkg.name));
// const ctx = app.mockContext({});
// yield ctx.service.xx();
});
// 编写期待的地址,期待的输出内容,期待的返回状态码
it('should GET /jspang', () => {
return app.httpRequest()
.get('/jspang')
.expect('<h1> you are jspang</h1>')
.expect(200);
});
});
2.服务( Service )
Service 就是在复杂业务场景下用于做业务逻辑封装的一个抽象层,service的使用场景就是当我们展现的信息需要从数据库中拿或者数据经过一定的计算规则之后更新到数据库。
- 保持业务逻辑的独立性,抽象出来的 Service 可以被多个 Controller 重复调用。
- 将逻辑和展现分离,更容易编写测试用例,测试用例的编写具体可以查看这里。
- 使得controller的使用更加的简洁。
service简单示例
// app/Service/jspang.js
'use strict';
const Service = require('egg').Service;
class jspangService extends Service {
async getGirl(id) {
return {
id: id,
name: '小红',
age: 11
}
}
}
module.exports = jspangService
// app/Controller/jspang.js下使用示例 (使用时别忘了router.js文件的配置)
async getGirls() {
const ctx = this.ctx;
// ctx.body = ctx.query;
const res = await ctx.service.jspang.getGirls('1');
ctx.body = res;
}
// app/controller/home.js
async testGetGirl() {
// 获取上下文
const ctx = this.ctx;
// 第1种:获取传递的参数
let id = ctx.query.id;
const res = await ctx.service.jspang.getGirls(id);
// 第2种: 直接传入参数
// const res = await ctx.service.jspang.getGirls(1);
ctx.body = res;
}
三. egg拓展 —— view中使用ejs模板
1. 为什么要用EJS引擎
对 SEO 非常友好
中台 一次登录 SPA
在egg项目中安装ejs
npm i egg-view-ejs --save
在egg项目中配置ejs
在egg的config文件夹下面的文件中配置(plugin.js)
'use strict';
/** @type Egg.EggPlugin 模板引擎*/
exports.ejs = {
enable: true,
package: 'egg-view-ejs'
};
在egg的config文件夹下面的文件中配置(config.default.js)
// 配置模板引擎, html中可以写ejs代码
exports.view = {
mapping: {
//以.html结尾的文件都可以使用ejs写法
'.html': 'ejs',
}
};
2. egg中ejs使用示例:
第一步,先在controller文件下的使用render
// app/controller/jspang.js
class jspangController extends Controller {
// get请求示例
async index() {
const { ctx } = this;
await ctx.render('jspang.html', {
id: 2021,
name: "小红",
age: 18,
skills: ['泰式按摩','搓背']
});
}
}
第二步:在app/view下创建html文件
<body>
<h1>欢迎来到这里</h1>
<h1>现在由<%= id %> 号技师<%= name%>为你服务</h1>
<h1>我的技能是</h1>
<ul>
<% for(var i=0;i<skills.length;i++){ %>
<li><%= skills[i]%></li>
<% } %>
</ul>
</body>
扩展:
还可以给html文件添加其它的html文件:
<%include header.html%>
或者添加css文件(css,js文件等在public/css(js)/下)
四. COOKIE和session
1.Cookie的基本操作
Cookie是在Web应用中承担识别请求方身份的功能,web应用在cookie的基础上封装了 session的概念,专门用做用户身份的识别。
Cookie的增 删 改 查
- ctx.cookies.set(key,value,options) 如: ctx.cookies.set(key,value,{signed:false,})
- ctx.cookies.get(key,options) 如:ctx.cookies.get(key,{ signed: false})
// 在html文件中
<div>
<button onclick="add()">增加cookie</button>
<button onclick="del()">删除cookie</button>
<button onclick="editor()">改变cookie</button>
<button onclick="show()">查看cookie</button>
</div>
<script>
// 增删改查cookie的方法进行定义
function add() {
fetch('/add', {
method: 'post',
headers: {
// 安全策略
'Content-type': 'application/json'
}
})
}
function del() {
fetch('/del', {
method: 'post',
headers: {
// 安全策略
'Content-type': 'application/json'
}
})
}
function editor() {
fetch('/editor', {
method: 'post',
headers: {
// 安全策略
'Content-type': 'application/json'
}
})
}
function show() {
fetch('/show', {
method: 'post',
headers: {
// 安全策略
'Content-type': 'application/json'
}
})
}
</script>
// 在controller的js文件中 (别忘了在router文件中匹配路由)
async add() {
const ctx = this.ctx;
// 对cookie的一些基本操作
ctx.cookies.set('user','jspang.com', {
maxAge: 1000*60,
httpOnly: false,
encrypt: true // 加密传输
});
// 添加session
ctx.session.username = 'jspang'
ctx.body = {
status: 200,
data: "cookie添加成功"
}
}
// 删除cookie
async del() {
const ctx = this.ctx;
ctx.cookies.set('user', null);
ctx.body = {
status: 200,
data: "cookie删除成功"
}
}
// 修改cookie
async editor() {
const ctx = this.ctx;
ctx.cookies.set('user', 'bilibili.com');
ctx.body = {
status: 200,
data: "cookie修改成功"
}
}
async show() {
const ctx = this.ctx;
const user = ctx.cookie.get('user');
ctx.body = {
status: 200,
data: 'cookie查看成功'
}
}
}
options的一些基本选项:
- { Boolean } signed: 设置对cookie进行签名,如果设置为true, 则设置键值对的时候会同时对这个键值对的值进行签名,后面取的时候做校验,可以防止前端对这个值进行篡改。
- { Boolean } httpOnly: 设置键值对是否可以被js访问, 默认为true, 不允许被js访问。
- {Boolean} encrypt:设置是否对 Cookie 进行加密,如果设置为 true,则在发送 Cookie 前会对这个键值对的值进行加密,客户端无法读取到 Cookie 的明文值。默认为 false。
2.session的基本操作
在框架中内置session插件,给我们提供了ctx.session来访问或者修改当前用户的session
// 在添加cookie对应的controller文件中去添加session
// 1.添加session (add)
ctx.session.username = 'jspang';
// 2.获取session (index)
const username = ctx.sesison.username;
await ctx.render('jspang.html', {
id: 2021,
name: "小红",
age: 18,
skills: ['泰式按摩','搓背'],
username: username
});
// 3.查看session (HTML文件)
<!-- 查看session -->
<%= username %>
// 其它操作 (删除,修改)
ctx.session.username = null;
// 重新赋值即可进行修改
ctx.session.username = '技术胖'
五. 使用egg的扩展
egg可以对内部的对象进行扩展,application,content,response,request
| 对象 | 说明 | this指向 | 使用方法 |
| application | 全局应用对象 | app对象 | this.app |
| content | 请求上下文 | ctx对象 | this.ctx |
| response | 提供了响应的属性和方法 | ctx.response对象 | this.ctx.response |
| request | 提供了请求的属性和方法 | ctx.request对象 | this.ctx.request |
| helper | 帮助函数 | ctx.helper对象 | this.ctx.helper |
1.对application对象的方法扩展
(1)// app/extend/application.js
module.exports = {
// 方法扩展
currentTime () {
return getTime();
},
// 属性扩展
get timeProp () {
return getTime();
}
}
function getTime () {
let now = new Date();
let year = now.getFullYear();
let month = now.getMonth() + 1;
let day = now.getDate();
let hours = now.getHours();
let minutes = now.getMinutes();
let seconds = now.getSeconds();
let nowTime = year + '年' + month + '月' + day + '日' + hours + '时' + minutes + '分' + seconds + '秒';
return nowTime;
}
(2) 在app/controller/jspang.js中去取得这个值
class jspangController extends Controller {
async index() {
const { ctx, app } = this;
await ctx.render('jspang.html', {
nowTime: app.currentTime(),
nowTimeProp: app.timeProp
});
}
(3) 在app/view/jspang.html中查看这个值
<%= nowTime %>
<%= nowTimeProp%>
2.对context对象的方法扩展
1)// app/extend/context.js
module.exports = {
// 编写params方法
params(key) {
const method = this.request.method;
if(method === 'GET') {
return key ? this.query[key]:this.query;
}else {
return key? this.request.body[key]: this.request.body;
}
}
}
(2) 在app/controller/jspang.js中去取得这个值
// 练习context对象的demo
async newContext() {
const ctx = this.ctx;
const params = ctx.params('username');
const paramsOne = ctx.params('');
console.log(params); //jspang
console.log(paramsOne); //{ username: 'jspang' }
ctx.body = 'newContext';
}
3.对request对象的方法扩展
1)// app/extend/request.js
module.exports = {
get token() {
console.log('token',this.get('token'))
return this.get('token');
}
}
(2) 在app/controller/jspang.js中去取得这个值
// 练习request对象的demo
async newRequest() {
const {ctx} = this;
const token = ctx.session.token;
ctx.body = {
status: 200,
body: token
}
}
4.对response对象的方法扩展
1)// app/extend/response.js
module.exports = {
set token(token) {
return this.set('token',token);
}
}
(2) 在app/controller/jspang.js中去取得这个值
// 练习response对象的demo
async newResponse() {
const {ctx} = this;
ctx.response.token = 'jspang.com'
// 练习helper对象得扩展
const testBase = ctx.helper.base64Encode('jspang.com')
ctx.body = testBase
}
匹配路由
// 扩展对象匹配路由 (application)
router.get('/newApplication', controller.jspang.newApplication)
// 扩展对象匹配路由 (context)
router.get('/newContext',controller.jspang.newContext);
// 扩展对象匹配路由 (request)
router.post('/newRequest',controller.jspang.newRequest);
// 扩展对象匹配路由 (response)
router.get('/newResponse',controller.jspang.newResponse);
六. 使用egg操作数据库
1.配置数据库
- 安装 npm i --save egg-mysql
- 配置如下:
// config/plugin.js exports.mysql = { enable: true, package: 'egg-mysql' }; // config/config.default.js exports.mysql = { // 单数据库信息配置 client: { // host host: 'mysql.com', // 端口号 port: '3306', // 用户名 user: 'test_user', // 密码 password: 'test_password', // 数据库名 database: 'test', }, // 是否加载到 app 上,默认开启 app: true, // 是否加载到 agent 上,默认关闭 agent: false, };2.操作数据库
controller/girlManage.js(创建view和model之间的联系)
'use strict';
const Controller = require('egg').Controller;
class girlManage extends Controller {
// 增
async addGirl() {
const {ctx} =this;
// 编写要添加到数据库的信息(在service中添入)
const params = {
name: '小白',
age: 18,
skill: '头疗'
}
const res = await ctx.service.testdb.addGirl(params);
ctx.body = '添加女孩';
}
// 删
async delGirl() {
const {ctx} = this;
const id = {id: 3}
const res = await ctx.service.testdb.delGirl(id);
if(res) {
ctx.body = '删除女孩——成功'
}else {
ctx.body = '删除女孩——失败'
}
}
// 改
async updateGirl() {
const {ctx} = this;
const params = {
id: 1,
name: '小红',
age: 18,
skill: '头疗'
}
const res = await ctx.service.testdb.updateGirl(params);
if(res) {
ctx.body = '修改女孩——成功'
}else {
ctx.body = '修改女孩——失败'
}
ctx.body = '修改女孩'
}
// 查
async getGirl() {
const {ctx} = this;
const res = await ctx.service.testdb.getGirl();
ctx.body = '查询女孩' + JSON.stringify(res);
}
}
module.exports = girlManage;
'use strict'
const Service = require('egg').Service;
class testdbService extends Service {
// 增
async addGirl() {
try {
const app = this.app;
const res = app.mysql.insert('girls', params);
return res;
}catch (error) {
console.log(error);
return null;
}
}
// 删
async delGirl() {
try {
const {app} = this;
const res = app.mysql.delete('girls', id)
return res;
}catch (error) {
console.log(error);
return null;
}
}
// 改
async updateGirl() {
try {
const app = this.app;
const res = app.mysql.update('girls', params);
return res;
}catch (error) {
console.log(error);
return null;
}
}
// 查
async getGirl() {
try {
const app = this.app;
const res = app.mysql.select('girls');
return res
}catch(error) {
console.log(error);
return null;
}
}
}
module.exports = testdbService;
// 数据库的增删改查示例路由配置
router.get('/addGirl',controller.girlManage.addGirl);
// 数据库的增删改查示例路由配置
router.get('/delGirl',controller.girlManage.delGirl);
// 数据库的增删改查示例路由配置
router.get('/updateGirl',controller.girlManage.updateGirl);
// 数据库的增删改查示例路由配置
router.get('/getGirl',controller.girlManage.getGirl);
1050

被折叠的 条评论
为什么被折叠?



