0X00
- 这里基于我的情况,需要快速上手
0X01 基于Egg框架的项目启动
- 找到目录中的
package.json
,点击右键show npm scripts
,然后dev run
,dev run
是属于在测试环境中的模式,如果在win环境下跑run
的话会出现好多窗口,是因为有多少启动了多个线程,就出现了那么多的窗口
0X02 Egg基本目录结构
controller
文件夹和java的一样extent
属于可选的,可以对框架进行扩展配置,详情见框架扩展model
是属于Egg的自定义目录规范,详情Loader APIpublic
属于可选,放置静态文件,详情egg-staticservice
和java的service层一样router.js
这个主要是路由的配置,相当于servlet配置映射的路径,这个还是比较重要的
0X03 基于RESTful风格的简单的CURD
0.Egg中规定的RESTful的请求
ctx
的含义
ctx - 当前请求的 Context 实例。
- Egg中规定的RESTful的请求
1.简述思路
- 这里举一个新闻的例子,对新闻进行CURD操作,从
model
层开始编写,在编写controller
层,最后在配置路由router.js
配置出RESTful风格的接口(这里不用编写service
层是因为我controller
继承了一个公共类,其中有最基础的CURD方法,所以说这次上手还是感觉比较简单)
2.Model层的编写,实体的写法
- 下面是一个新闻的实体
1 | ; |
use strict
表示使用严格模式
为什么用严格模式- 消除代码运行的一些不安全之处,保证代码运行的安全;
- 提高编译器效率,增加运行速度;
- 为未来新版本的Javascript做好铺垫。
app.mongoose
调用mnogoDB插件const tempSchema
表示mnogoDB的数据库类型?(暂时不确定,没有使用过mnogoDB)5到10行就是字段
versionKey: false,
这个一个是个标准的写法吧return mongoose.model('news', tempSchema);
这个可以对应到service
层
3.编写Controller层
- 下面的新闻的controller
1 | ; |
这里第一行也是使用严格模式,提高编译和运行速度
const CommonController = require('./commonController');
这是相当于java的导包操作,把commonController
引用到当前类中(es6有class的写法)第五行和java的class写法一样
extends
也一样表示继承init()
表示初始化service
层(感觉在egg框架还是es6的语法规则中,比如你要调用service
层或者你要调用model
层的实体的话,都是需要先进行init()
进行初始化),虽然这里并没有用到新闻的service
层CRUD(那增加进行举例)
1
2
3
4async create (ctx) {
await super.create(ctx);
ctx.logger.debug("增加");
}
async
表示使用异步的方式,await
表示必须等到suoer.create
的返回值在进行下一步
在下面就是日志记录
4.简单介绍一下service层的写法
- 虽然简单的CURD我是基于现成的类进行编写的(在框架整合了简单的curd),但是在真实的业务情况中这些简单的CURD肯定是无法满足业务需求的,所以这里需要新的
service
层
下面是例子
1 | ; |
这里还是要先进行
init()
方法初始化自定义的方法编写到
daoService
中,这里进行引用应该就可以了
5.处理路由router.js
- 路由还是比较简单的,但是我觉得还是重要
下面是路由配置
1 | ; |
这里一样是使用严格模式
const api = '/api/v1'
规定请求路径module.exports = app => {}
标准写法const { router, controller } = app;
这个应该也是标准写法router.post(api + '/surveyRecords/search', controller.surveyRecords.index);
这个是post请求到controller
文件夹下的surveyRecords.js
文件中的index
方法router.resources('news', api + '/news', controller.news);
这个是整合了post啊get啊那些的RESTful风格,可以根据你的请求进行自动访问规定的方法
0X04接口分析(居家养老服务管理系统)
0.登录接口
A. 路由
router.get(api + ‘/users/login’, controller.users.login);
B. Controller层代码
1 | async login(ctx) { |
if (user && user.roles)
user不为空,user.roles不为空Object.keys()
返回一个数组if (Array.isArray(user.roles[s]))
判断是不是数组getRolesBySystem()
C. Service层代码中的
login()方法
1 | async login(phone, password) { |
1.通过controller层的
const user = await this.service.users.login(ctx.query.phone, ctx.query.password);
调用到service层来2.
const md5Pass = this.ctx.helper.md5(password);
调用help层(相当于java的util)进行MD5处理3.
$or
是个重点,这里举一个官方例子:
1 | db.inventory.find( { $or: [ { quantity: { $lt: 20 } }, { price: 10 } ] } ) |
意思是取出inventory(存货) 集合,条件在$or
中分别有两个条件,第一个是quantity字段的值小于20或者price字段等于10,$lt
的意思就是小于某个值(以后会有更详细的文章来介绍MongoDB的语法)
4.
$or: [{phone}, {shortName: phone}], password: md5Pass
先来大概分析这句的意思,肯定有两个条件$or
中是一个条件,逗号后面是一个条件。
在来分析$or
中的条件,$or
肯定是有两个条件,系统可以用两种账号来进行登录,第一个种是手机也就是phone字段,第二种是短命登录也就是shortName字段,{phone}
相当于{phone:phone}
,我猜测用{phone}
简写是因为在数据库的字段和这里的字段是一样的。
第一个条件就分析完了,在来分析第二个条件也就是password: md5Pass
这个没有$or
说明这个值是一个必须满足的条件。
最后在梳理一下,假如传入参数为phone=110,password=123,那么这条语句的意思是在数据库中查找phone字段等于110,或者shortName字段等于110,同时满足password字段=1235.
return await this.model.findOne(queries).lean();
model层的实体都有一些默认的方法,findOne()就是其中一个,这里传入的参数就是上面拼接的MongoDB数据库语句6.
lean()
这里单独说一下lean()
,不加这个方法的话他返回的对象中就带有model的一些默认方法,所以要加这个方法
getRolesBySystem()方法
1 | async getRolesBySystem(userRoles, system) { |
- 接收到传入的userRoles数组 和system(相当于Key)