如果需要了解Controller ,就得知道什么是mvc。
什么是mvc,这个概念,我相信绝大部分人肯定是了解的。MVC是模型(model)- 视图(view)- 控制器(controller)的缩写。MVC是一种软件设计规范,主要作用就是逻辑拆分:
ps:这一整套流程实际上是一个闭环,你可以这么去理解,就是用户输入给控制器,然后控制器将用户输入的指令和数据传递给业务组件,业务组件进行业务逻辑判断,数据库存取,将要展示的数据返回到视图,用户得到了反馈,在进行下一步的操作。
this.ctx可以获取到当前请求的上下文对象,通过此对象可以便捷的获取到请求与响应的属性与方法。
我们可以拿最初的模板案例来解析,controller文件夹下面的home.js文件:
'use strict'; //严格模式
const Controller = require('egg').Controller; //Controller类
class HomeController extends Controller { //定义一个新的类去继承Controller类
async index() {
const { ctx } = this;
ctx.body = '你好egg';
}
}
module.exports = HomeController; //暴露HomeController
这个严格模式,写和不写都可以,没必要说一定要写,这个也不是egg特有的,因为egg已经给我们封装好了控制器的方法,所以我们只需要调用就好了,然后继承暴露出来,最简单的一个控制器我们就写好了。
接下来,尝试写一个水果控制器,首先要在controller文件夹下创建fruits.js,然后我们模仿home.js进行编写。
'use strict'; //严格模式
const Controller = require('egg').Controller; //Controller类
class FruitsController extends Controller {
async index() {
this.ctx.body = '我是一个水果列表'
}
}
module.exports = FruitsController
此时,我们写完,想要去访问这个页面,肯定是需要路由去访问的,所以,我们需要去编写router.js这个文件,来访问我们刚刚写的水果页面。
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.get('/fruits', controller.fruits.index);
};
通过这个代码,我们可以看出来,这个是通过暴露一个函数,这个app是一个形参,是egg应用里的一些实例。
然后通过结构赋值的方法,我们拿到了,router和controller这两个对象。
然后通过路由的get方法去规定跳转的路由地址,以及展示的是controller目录下面的home文件里的index方法。
所以我们访问地址是’/‘看到的就是’hi,egg’,所以我们模仿一下,加上router.get(‘/fruits’, controller.fruits.index); 就能通过访问’/fruits’实现访问上面写的水果页面了。
我们在控制器里靠一个属性去获取get请求的query,this.ctx.request.query,然后我们只要在url后面拼上传递的数据,就能获取到了,http://127.0.0.1:7001/fruits?index=100
'use strict'; //严格模式
const Controller = require('egg').Controller; //Controller类
class FruitsController extends Controller {
async index() {
let query = this.ctx.request.query
this.ctx.body = `传递的index的值是${query.index}`
}
}
module.exports = FruitsController
首先我们要在router.js里面加上一行router.get(‘/fruits/:id’, controller.fruits.getId),我们重新写一个getId的方法。
async getId() {
let id = this.ctx.params.id
this.ctx.body = `传递的id的值是${id}`
}
然后我们只要在url后面加上’/100’就能获取到了,http://127.0.0.1:7001/fruits/100
拓展:那么如果你想传多个参数,就继续往后面拼就可以了router.get(‘/fruits/:id/:title’, controller.fruits.getId),拿的话,也和上面一样let title = this.ctx.params.title。
说完了query以及params的get请求呢,接下来就是query和params的post请求了,这个稍微难一点。获取post请求参数:this.ctx.request.body。
举个例子实现,表单提交是post请求,我们可以通过实现表单提交来获取post的参数,那么,我们可以通过提交表单,插入数据到列表里面。
第一步:要创建数组,和类同级
let fruitList = ["香蕉", "苹果", "西瓜"]
第二步:有了数组,我们就需要一个页面去展示这个数组
async getList() { //获取水果列表
this.ctx.body = fruitList
}
router.get('/fruitList', controller.fruits.getList);
第三步:构建表单页面
async createPage() { //提交表单
this.ctx.body = `
`
}
router.get('/createPage', controller.fruits.createPage);
第四步:我们需要输入,然后将输入的内容插入到水果列表里面,首先我们要修改一下createPage方法,加入请求方法为post,提交的地址也要加上。
async createPage() {
this.ctx.body = `
`
}
async creatFruit() { //获取提交的水果数据
let fruit = this.ctx.request.body
this.ctx.body = fruit
}
router.post('/creatFruit', controller.fruits.creatFruit);
第五步:输入水果,提交表单,发现,页面显示403
之所以有这个情况,是因为CSRF指跨站请求伪造,Egg中对post请求做了一些安全验证,可以在config.default.js文件中,通过下面的设置验证。
config.security = {
csrf:{
enable:false
}
}
配置好这个,我们再次输入水果,再次点击提交,此时,我们成功跳转到了’/createFruit’页面
第六步:也就是最后一步,我们需要提交跳转的页面,将数据插入到原先的列表里面去
async creatFruit() {
let fruit = this.ctx.request.body
fruitList.push(fruit.fruitName)
this.ctx.body = '添加成功'
}
此时,我们输入提交会出现 ‘添加成功’的字样,然后我们在跳转会’/fruitList’就会看到输入的内容已经被插入了
//fruits.js
'use strict'; //严格模式
const Controller = require('egg').Controller; //Controller类
let fruitList = ["香蕉", "苹果", "西瓜"]
class FruitsController extends Controller {
//index方法 用于获取query的get请求参数
async index() {
let query = this.ctx.request.query
this.ctx.body = `传递的index的值是${query.index}`
}
//getId方法 用于获取params的get请求参数
async getId() {
let id = this.ctx.params.id
let title = this.ctx.params.title
this.ctx.body = `传递的id的值是${id},传递的title是${title}`
}
//getList方法 用于展示水果列表
async getList() {
this.ctx.body = fruitList
}
//createPage方法 用于表单提交页面
async createPage() {
this.ctx.body = `
`
}
//插入提交的水果
async creatFruit() {
let fruit = this.ctx.request.body
fruitList.push(fruit.fruitName)
this.ctx.body = '添加成功'
}
}
module.exports = FruitsController
//router.js
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const {
router,
controller
} = app;
router.get('/', controller.home.index); //默认页
router.get('/fruits', controller.fruits.index);
router.get('/fruits/:id/:title', controller.fruits.getId)
router.get('/fruitList', controller.fruits.getList);
router.get('/createPage', controller.fruits.createPage);
router.post('/creatFruit', controller.fruits.creatFruit);
};
到这里,post的请求方法拿参数完成了,不过,往回看路由,会发现,我们写的很多,get写一个,post写一个,如果后面说,一个地址里面,引入了好多的方法,那会越写越多,所以这里egg为了简单写法,给出了新的形式。
restful风格的url可以简化路由文件
格式:app.router.resources(‘routerName’, ‘pathMatch’, controller)
router.resources('posts','/api/posts',controller.posts) //一个方法同时定义增删改查
我们来简化一下之前的路由,全部隐藏,你可以删除,然后写上
router.resources('fruits', '/fruits', controller.fruits)
根据表格的对对照关系,我们将fruits.js修改一下
async index() {
this.ctx.body = fruitList
}
async new() {
this.ctx.body = `
`
}
async create() {
let fruit = this.ctx.request.body
fruitList.push(fruit.fruitName)
this.ctx.body = '添加成功'
}
首先这个index方法,对应表格里面的get请求,就把之前的getList的方法内容移到index方法里面
就是index方法专门去获取水果列表,表里对应的new方法,放表单的提交内容
有一点要注意,就是我们提交时候的action地址要变成router.js里面写的地址,creat方法对应的是post请求,所以我们放拿到参数的一系列操作。然后我们回到页面,在地址栏上输入’/fruits’,就能看到列表,输入’/fruits/new’,就会来到提交表单页面。
最后我们完善一下这个demo,添加成功,返回到水果列表的页面,我们只需要用this.ctx.redirect(‘/fruits’)就能重定向到水果列表页面
//router.js
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const {
router,
controller
} = app;
router.get('/', controller.home.index); //默认页
router.resources('fruits', '/fruits', controller.fruits)
};
//fruits.js
'use strict'; //严格模式
const Controller = require('egg').Controller; //Controller类
let fruitList = ["香蕉", "苹果", "西瓜"]
class FruitsController extends Controller {
//index方法 用于获取query的get请求参数
async index() {
this.ctx.body = fruitList
}
//createPage方法 用于表单提交页面
async new() {
this.ctx.body = `
`
}
//插入提交的水果
async create() {
let fruit = this.ctx.request.body
fruitList.push(fruit.fruitName)
//跳转到/fruits get请求
this.ctx.redirect('/fruits')
}
}
module.exports = FruitsController