到目前为止,我们其实使用的是
egg的脚手架,脚手架在一开始就帮助我们搭建了大部分的结构和基本可运行的代码框架。所以我们这次只下载egg库从零开始手动搭建和学习egg项目。
1.npm初始化
npm指令生成package模块配置文件
npm init -yse
init即初始化,-yes可以理解为一个参数,告诉程序init初始化时任何选择都是自动yes选择。
- package.json文件:
{
"name": "work2",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
其中scripts的简写指令都可以通过npm run xxx的方式执行。所以我们向里面添加egg服务器启动指令:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "egg-bin dev"
},
执行npm run dev等于执行egg-bin dev指令。
2.安装egg.js框架库
- 指令和效果:
npm i egg -save
npm i egg-bin --save-dev
egg-bin是开发必须使用的egg插件库。
安装egg.js库的时候,egg内置的模块和插件都将一并下载配置,所以产生了模块配置package-lock.json文件,node_modules文件夹。
- 启动egg项目
npm run dev
第一次执行后将会在项目根目录产生log文件夹。
3.创建public路径
public是egg.js库是默认支持的路由,可以理解为node通过fs实现的路由静态资源访问。这个可访问静态资源路由为:项目文件/app/public
- 所以我们按照设计好的路由,进行创建:
- 创建html文件并尝试访问:
4.搭建控制层controller
在app文件夹内创建一个controller文件夹,用于编写控制层接口代码。前面我们没有仔细讲解controller是做什么的,其实这个概念常见于后端,对于前端开发人员来说我们,知道controller是负责处理请求 响应请求的api(对象和方法)集合就足够了(个人拙见)。
所以我们需要单独创建controller文件夹存储编写controller层代码。我们编写每个的controller模块都需要继承egg库中的controller基类,并导出,因为是模块化所以,我们可以编写多个api接口的同时,也可以写多个controller模块,每个模块处理只包含业务类似的api。
controller层的模块文件结构:
//app\controller\index.js
const Controller = require('egg').Controller;
class IndexController extends Controller{
async index(){
//业务代码
}
}
module.exports = IndexController
controller层模块通常写法:
async index(){
//使用ctx对象,编写请求和响应业务代码, const { ctx } = this 和下面代码是一样的效果。
const ctx = this.ctx
//业务代码,ctx.query、ctx.request.body、ctx.body等
......
//service层代码,操作service层,完成对数据库的操作。
const service = ctx.service
......
}
5.搭建路由文件
路由文件即router.js文件。直接接受网站发送的请求,并执行对应的控制层代码。
//app\router.js,导出的是一个箭头函数。
module.exports = app => {
const { router , controller } =app;
//设置路由
router.get()
router.post()
}
虽然路由并不直接完成业务代码,但是作为连接请求和控制层的模块,帮助我们理清了业务逻辑,指明了具体的请求路由是由什么控制模块去处理。
6.请求所需的插件
配置层
config下个标题讲解,先讲请求会用到的插件。
请求所需的插件无非是跨域cors和CSRF安全问题。cors即跨域资源共享,我们使用npm指令安装该egg库对应插件:
npm egg-cors --save
下载安装只是在node_modules文件夹中下载了这个模块,我们还需要在项目中使用,首先通过config配置层中的plugin.js进行配置:
//plugin.js
exports.cors = {
enable: true,
package: 'egg-cors',
};
而CSRF相关的插件是egg-security,egg库是内置了的,所以不需要下载安装和启动,但是需要配置,这里我们将二者一起配置。
//config.default.js
exports.security = {
csrf: {
enable: false,
ignoreJSON: true,
},
domainWhiteList: [ '*' ],
};
exports.cors = {
origin:'*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',
};
主要三个步骤:下载到模块文件夹内》plugin.js文件内启用》config.default.js文件内配置。
我们这里之所以与前面写的方式不一样是因为模块化的开发具有多种写法,都是exports导出模块内容的作用。
7.配置信息config文件夹
整个文件夹都是基于模块化的设计模式,虽然配置在js文件内,但是最终都是要被导出来,每个配置信息都在导出的对象内。
egg脚手架格式:
'use strict';
/**
* @param {Egg.EggAppInfo} appInfo app info
*/
module.exports = appInfo => {
/**
* built-in config
* @type {Egg.EggAppConfig}
**/
const config = exports = {
cluster: {
listen: {
path: '',
port: 80,
hostname: 'juejinjin.com',
},
},
};
// add your config here
config.security = {
csrf: {
enable: false,
ignoreJSON: true,
},
domainWhiteList: [ '*' ],
};
config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',
};
// use for cookie sign key, should change to your own and keep security
config.keys = appInfo.name + '_1631862053127_8161';
// add your middleware config here
config.middleware = [];
// add your user config here
const userConfig = {
// myAppName: 'egg',
};
return {
...config,
...userConfig,
};
};
手写简化版:
//config.default.js
exports.keys = "fdsafdsafdsa";
exports.security = {
csrf: {
enable: false,
ignoreJSON: true,
},
domainWhiteList: [ '*' ],
};
exports.cors = {
origin:'*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',
};
这里我们比较了config.default.js文件,可以看到明显的区别,通过整合的方式更加规范,但是通过多个导出的方式代码量更少(相对而言)。
都是通过导出的方式,将配置信息导出,plugin.js文件是一样的,不同的只是egg库设计下分工,严格限制了路径和名字:
//plugin.js
exports.cors = {
enable: true,
package: 'egg-cors',
};
...//同样的格式我们还可以启用例如egg-mysql模块等。
本次学习中建议手写,帮助理解和学习,日常开发建议使用egg脚手架的格式编写代码。
8.数据库和Service层(业务层)
前面我说了controller层,也就是控制层,负责处理请求和响应,而这里提出的Service层则是负责和数据库的交互(简单概括),controller层的模块根据具体需要选择调用Service层模块完成数据库操作等需求。
我们编写Service层的结构和controller层是相似的,创建一个Service文件夹用于存放业务层js模块。
而业务层模块的写法也是类似的模块化设计,不同的只是用于区别的js模块名和具体的方法名。都继承了Service基类,同时因为要导出,所以class名字只是其阅读区别的功能,但是仍然建议区别写每个模块的class名。
//app\service\index.js
const Service = require('egg').Service;
class IndexService extends Service{
async index(){
// 具体业务代码,比如使用egg-mysql模块,对数据库进行操作。
}
}
module.exports = IndexService
因为Service层和数据库操作基本分不开,所以我们是需要下载egg-mysql插件才能很好的进行业务层开发。
npm egg-mysql --save
//config\plugin.js
exports.mysql = {
enable: true,
package: 'egg-mysql',
};
安装和启动代码和步骤,相信各位一路走来基本都很熟悉了,数据库插件的难点主要是配置信息:
//config\config.default.js
exports.mysql = {
client: {
host: 'localhost',
port: '3306',
user: 'root',
password: '123456',
database: 'test',
},
app: true,
agent: false,
}
这里我们将mysql配置对象单独导出,每个参数具体的作用我建议到我的写篇文章之egg——(6)egg服务器操作mysql中学习一下。这里只提供截图:
如果你还无从下手,请查看我的egg专题博客的前面文章,其实每个部分的具体功能代码无论手不手写都是一样的,这章只是教大家如果从零搭建项目,就是手动的完成egg脚手架初始化的那一步。
到此我们基本了解egg项目的结构,通过手写我们同样可以搭建一个可运行,能够具有完整效果的egg项目。随着深入的学习我们还将进一步解析新的结构和关系。