egg:为企业级框架和应用而生 ,可以降低开发和维护成本,遵循约定优于配置 ,按照统一的约定来进行项目开发。
egg框架约定的目录结构:
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
1、创建一个目录作为项目名称
2、安装egg(在Node安装好的基础上,当安装了cnpm时,以下所有的npm都可以用cnpm代替):
npm init
npm i egg --save
npm i egg-bin --save-dev
3、在生成的package.json文件中的scripts{}中加入"dev":“egg-bin dev”
4、在项目下创建config目录,在config目录下创建config.default.js文件,并在文件中随意加入一些字符串:
exports.keys = “dfbgffdsafddgfd”;
keys是必须的,keys的值可以随意(写字母)
1、在项目下创建app目录,在app目录下创建public目录:public是静态资源目录,该目录下可以放html、js、css、img等静态资源,启动项目后,访问静态资源的url为:http://localhost:7001/public/文件路径
2、示例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ApCsA0x1-1596455046935)(D:\华清学习\在线学习\Node\egg示例.PNG)]
3、启动项目:
在项目目录打开命令窗口,输入:npm run dev
4、在浏览器输入网址(如上图的文件为例):http://localhost:7001/public/index.html
1、在项目下app目录下面创建目录constroller,所有的控制层都必须放在这个目录下
2、在constroller下创建js文件
hello.js固定格式:
//得到Controller类
const Controller = require('egg').Controller;
//自定义一个类,并且必须继承Controller类,自定义类名随意
class HelloController extends Controller {
//创建原型函数,函数名自定义
async getHello() {
this.ctx.response.body = "这是Hello!";
}
}
//导出自定义类
module.exports = HelloController;
stu.js固定格式:
const Controller = require('egg').Controller;
class StuController extends Controller {
async show1() {
this.ctx.response.body = "这是get得到的信息";
}
async show2() {
this.ctx.response.body = "这是post得到的信息";
}
}
module.exports = StuController;
3、创建路由app/router.js:有get和post两种方法,他们分别由两个参数,参数1是请求url,参数2是controller.文件名.方法名
module.exports = app => {
//解构赋值,app是一个对象
const { router, controller } = app;
//可以改成这样
// const router = app.router;
// const controller = app.controller;
//get请求
// controller映射controller文件夹
//hello映射hello.js文件
//getHello映射getHello函数
router.get('/hello', controller.hello.getHello);
router.get('/show1', controller.stu.show1);
//post请求
router.post('/show2', controller.stu.show2);
};
4、在config.default.js中加入关闭安全验证的,否则post请求会失败:
exports.security = {
csrf: false
};
5、所有的js文件都不能以大写字母开头,遵循小驼峰法
在controller或service中使用this.ctx即可获取到
以stu.js为例:
const Controller = require('egg').Controller;
class StuController extends Controller {
// constructor(){
// this.name = '小明';
// }
async show1() {
// console.log(this.name);
// this.ctx获取上下文对象
// this.ctx.response响应对象,将数据传送给客户端
// body的值就是要返回给客户端的值
this.ctx.response.body = "这是get得到的信息";
}
async show2() {
this.ctx.response.body = "这是post得到的信息";
}
}
module.exports = StuController;
1、在app下创建service目录
2、在service目录下创建一个stuService.js文件:
//导入service莫苦熬
const Service = require('egg').Service;
class StuService extends Service {
async getAllStu() {
return [{ id: 1, name: "巧姐" }, { id: 2, name: '贾探春' }];
}
}
module.exports = StuService;
3、在controller目录下的stuService.js中的自定义类中添加异步的showAllStu方法:
async showAllStu() {
//ctx.service.文件名.方法名, 调用service方法时,前面一定要加上await
let stuList = await this.ctx.service.stuService.getAllStu();
this.ctx.response.body = stuList;
}
在此处如果要尝试运行,需要先在router中添加:
// /showAllStu.do是为了避免重名
router.get('/showAllStu.do', controller.stuController.showAllStu);
请求方式有两种:get、post
对于get,使用ctx.request.query.key
对post,使用ctx.request.body.key
创建路由时说到这两种请求方式都有两个参数,他们的参数都可以在controller或service中获取,所以他们都是使用this.ctx来获取上下文对象(以下例子中的数据在实际开发中都可以获取用户输入或者从数据库获取)。
在html界面要发送ajax请求时,一般使用axios框架,它的写法是固定的,ajax请求可以做到异步请求和局部刷新,如果需要跳转到其他网页需要在其中加上location.href = url。
引入:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
基本写法:
//get请求
//path要和router中的router.get('path',controller)路径相同
axios.get('path',{
params: {
//一个对象,表示用户输入的数据,可以写成语法糖形式
}
}).then(res => {
//res.data是从服务器返回的数据
}).catch(err => {
//出现错误时
})
//post请求
//path要和router中的router.post('path',controller)路径相同
axios.post('path',{
//post参数不需要用params包裹
id: 123,
name: '张'
}).then(res => {
//res.data是服务器返回的数据
}).catch(err => {
//错误时
})
控制层testController.js:
async getString() {
let id = this.ctx.request.query.id;
let name = this.ctx.request.query.name;
console.log(id,name);
this.ctx.response.body = "getString!!!!";
}
async getNumber(){
let id = this.ctx.request.body.id;
let name = this.ctx.request.body.name;
console.log(id, name);
this.ctx.response.body = 'getNumber!!!!';
}
async postObj(){
let stu = {
id: 1001,
name: '小王'
}
console.log(stu);
this.ctx.response.body = 'postObj!!!!' + ','+ stu.id +',' + stu.name;
}
async getStringArr(){
let stringArr = ['aa','bb','cc','dd'];
this.ctx.response.body = stringArr;
}
async getObjArr(){
let a = [
{
id: 1,
name: '小张',
age: 20
},
{
id: 2,
name: '小明',
age: 30
}
];
this.ctx.response.body = a;
}
index.html:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
function getStr1(){
let inf = document.getElementById('inf');
//路径要与router中的路径相同
axios.get('/getString.do',{
params: {
id: 123,
name: '张'
}
}).then(res => {
inf.innerHTML = res.data;
}).catch(err => {
inf.innerHTML = '请求失败';
})
}
function getNumber(){
let inf = document.getElementById('inf');
axios.post('/getNumber.do',{
id: 123,
name: '张'
}).then(res => {
inf.innerHTML = res.data;
}).catch(err => {
inf.innerHTML = '请求失败';
})
}
function postObj(){
let inf = document.getElementById('inf');
//未传参
axios.post('/postObj.do',{}).then(res => {
inf.innerHTML = res.data;
}).catch(err => {
inf.innerHTML = '请求失败';
})
}
function getStringArr(){
let inf = document.getElementById('inf');
axios.get('/getStringArr.do',{
//未传参
}).then(res => {
inf.innerHTML = res.data;
}).catch(err => {
inf.innerHTML = '请求失败';
})
}
function getObjArr(){
let inf = document.getElementById('inf');
axios.get('/getObjArr.do',{
//未传参
}).then(res => {
let a = res.data//获取服务器返回的数据
let table = document.createElement('table');
table.innerHTML = 'id name age '
for(let i = 0; i < a.length; i++){
let tr = document.createElement('tr');
let td_1 = document.createElement('td');
td_1.innerHTML = a[i].id;
tr.appendChild(td_1);
let td_2 = document.createElement('td');
td_2.innerHTML = a[i].name;
tr.appendChild(td_2);
let td_3 = document.createElement('td');
td_3.innerHTML = a[i].age;
tr.appendChild(td_3);
table.appendChild(tr);
}
inf.innerHTML = '';
inf.appendChild(table);
}).catch(err => {
inf.innerHTML = '请求失败';
})
}
router.js:
router.get('/getString.do', controller.testController.getString);
router.post('/getNumber.do', controller.testController.getNumber);
router.post('/postObj.do', controller.testController.postObj);
router.get('/getStringArr.do', controller.testController.getStringArr);
router.get('/getObjArr.do', controller.testController.getObjArr);
get、post的区别:
(1)可以使用get请求和post请求,都可以传参也可以不传参
(2)post比get更安全、post对数据的多少没有限制,get请求数据大小有限制,一般不超过255个字符
(3)开发中使用get、post时要如何选择:
<1>如果是向服务器传送数据使用post————登录、注册
<2>向服务器端获取数据使用get请求
(4)他们传递的数据类型可以是Number、String、Object、Array等等
egg的内置对象有:
Application、Context、Request&Response、Controller、Service、Helper、Config、Logger
1、Context上下文对象,在使用时通常this.ctx,常在service和controller中使用
2、Application应用对象,全局的:
(1)使用方法:ctx.app或者this.app
(2)如何为Application对象加入属性和方法?
在 项目目录(该项目名称下)创建app.js文件,添加了属性和方法后可以在service或者controller中使用:
module.exports = app => {
app.mmm = '1mei';
app.show = () => {
console.log(app.mmm);
}
}
然后可以在service或者controller中去通过ctx.app访问到,其实app是一个全局的对象,我们创建app.js文件加入的内容只是在app对象上追加方法或属性。
3、Request和Response
获取客户端的数据:this.ctx.request
从服务器端返回数据:this.ctx.response
get请求:this.ctx.request.query.name 相当于 this.ctx.query.name
post请求:this.ctx.request.body.name 相当于 this.ctx.body.name
返回数据:this.ctx.response.body = 数据 相当于 this.ctx.body = 数据
4、内置对象helper
在app目录下创建extend目录,并创建helper.js文件:
module.exports = {
//helper文件名是固定的,其中的方法可以随意
help() {
return '这是调用了helper中的方法';
}
}
//通过ctx.helper来获取
5、Config
将全局需要的一些东西放在这里
在config目录的config.default.js文件中添加导出对象,可以随意命名:
exports.name = {
ua: [
/curl/i,
/Baiduspider/i,
]
};
获取时:
(1)在全局:app.config.name
(2)在Controller、Service、Helper中使用this.config.name来获取
6、Logger
用于记录运行过程,便于日后对项目出现的问题进行修改
7、Controller
一般我们做项目时写数据库操作在service中,但是要调用service中的方法时,还是要通过controller,在controller中,可以获取许多的对象:
(1)ctx:上下文对象,也叫作当前请求的context实例,通过this.ctx来获取
(2)app:应用的Application随想实例,通过this.ctx.app来获取
(3)config:应用的配置,使用this.config来获取
(4)service:应用所有的service,使用this.ctx.service来获取
(5)logger:为当前controller封装的logger对象