NEI 平台使用教程

规范化、自动化、云协作

包勇明 / @huntbao

内容介绍

  • 基本概念
  • 消息通知
  • 接口测试
  • 工程规范
  • 构建工具

基本概念

* 项目组和项目 * 项目资源 * 数据模型 * 异步接口 * 页面 * 页面模板 * 规则函数 * 业务分组

项目组和项目

现代产品的基本形态

![](/public/nei/product-a.png)

项目组和项目

![](/public/nei/project-group.png)

项目组 - 默认分组

* 用户首次登录时,系统会自动创建一个叫“默认分组”的项目组

项目组 - 创建者

* 鼠标 hover 到项目组名称上,会显示该项目组的创建者 * 在“团队管理”中查看该项目组的创建者

项目组 - 锁定

* 项目组被锁定后,切换到“只读”状态 > 锁定后,项目引用的工程规范还能修改,工程规范也可以被锁定

项目组 - 团队管理

* 在“团队管理”中,可以把其他人添加到项目组中 >人是加到项目组上的,而不是在项目上 --- >可以将其他项目组的成员一并导入

项目组 - 成员权限

* `创建者`:拥有所有操作权限 * `管理员`:拥有除删除项目组之外的所有操作权限 * `开发者`:拥有项目资源的所有操作权限,对项目组本身没有操作权限 * `测试者`:同“开发者” * `观察者`:“只读”权限 >除创建者外,其他角色都可以有多个

项目组 - 加入项目组

* 访问没权限的项目组或者项目时,会出现“申请加入”的按钮 >`搜索项目组/项目`:点击“我的项目组”,在“我的申请列表”区域的搜索框中输入项目组或者项目的名称

项目组 - 公共资源库

* 对于某个产品,有些资源对所有项目都是适用的,比如用户模型 User,登录接口等 ```json /* User Model */ { "id": "[number]", "name": "[string]", "email": "[string]" } ``` * 公共资源库,用来存放所有项目共享的资源,避免创建重复资源,以达到资源复用的目的 > 功能单一的资源才适合放到公共资源库

项目组 - 公共资源库

* 在创建项目组的时候,系统会自动创建“公共资源库” * 公共资源库中的资源会出现在所有项目中 >前面有黄色共享图标的表示是共享资源 --- >公共资源库只有异步接口、数据模型和规则函数 --- >`不要把公共资源库当作实际项目来使用`

项目组 - 共享资源

* 项目中的异步接口、数据模型、规则函数可以共享 * `资源被共享后,无法取消共享`,操作时须谨慎 > 共享资源的时候,还会将它所有引用的资源一并共享 --- > `如果不小心共享了某个资源,可以把它复制到目标项目,然后再将其删除`

数据模型

数据模型

* 最强大的功能之一,其他资源可以引用 * 修改时,所有引用它的资源都会更新,即引用并不会产生新的数据模型,数据库只存了一份数据

数据模型 - 用途

* 描述数据库实体,比如 Project、Page 等 * 复用,比如需要在多处使用的异步接口响应参数,它们有着相同的格式 >正确合理地使用数据模型,可以为之后的其他功能做好准备

数据模型 - 类别

共有七大类别,涵盖了编程语言的常见数据类型: * 哈希 * 枚举 * 数组 * 字符 * 数值 * 布尔 * 文件 >在新建数据模型时,请选择相应类别的单选按钮

数据模型 - 哈希

最常见的类型,比如 NEI 中的 Project: ```json /* Project Model */ { "id": "[number]", "name": "[string]", "type": "[string]", "creator": "[user]", "createTime": "[number]", "progroupId": "[number]", "toolKey": "[string]", "description": "[string]" } ``` > 字段的类型可以是任何数据模型,比如 creator 的类型是自定义类型 user

数据模型 - 哈希 - 可变字段

在定义时,有时某个字段的类型还无法确定,比如统一的异步接口返回参数格式: ```json { "code": "[number]", "message": "[string]", "result": "[variable]" } ``` 为了满足不同的应用场景,result 字段的类型可以是数组,也可以是对象,它的类型是 `variable`,表示类型是可变的。 >在使用这种数据模型时,需要明确指定 result 字段的类型

数据模型 - 哈希 - 创建方式

* 在第一行的第一个输入框,`粘贴JSON字符串` * 点击`导入JSON`按钮,和上述功能相同 * `导入其他数据模型`:会将导入的字段当作一个整体来对待,详情页面也做了特殊显示处理 * `从接口导入`:会识别接口返回的 JSON 数据,支持 GET 和 POST 两种类型的接口 * `从JavaBean文件导入`

数据模型 - 枚举

枚举的类型可以是字符串或者数值,枚举的值是必填的,键是选填的。比如 NEI 中的 `ProjectType`: | 值 | 类型 | 键(可选) | 描述 | | :--- | :--- | :--- | :--- | | 0 | number | | 常规项目 | | 1 | number | | 公共资源库 | | 2 | number | | 隐藏项目 | >类型也可以是自定义的字符串或者数值

数据模型 - 枚举

包含键名的枚举类型 `HttpStatusCode`: | 值 | 类型 | 键(可选) | 描述 | | :--- | :--- | :--- | :--- | | 200 | number | SUCCESS | 成功 | | 500 | number | FAIL | 失败 | >键在生成模型代码时会用到

数据模型 - 枚举 - 创建方式

* `导入其他枚举类型` * `从JSON导入`,此时导入的是值

数据模型 - 数组

NEI 中的数组有两种表示方式: * 在定义某个字段时,先选择类型 `Array`,多出来的另外一个下拉选择框表示数组元素的类型 * 直接定义数组类别的数据模型 >第一种表示方式是第二种的简便运用,两种表示方式是等价的

数据模型 - 数组 - 多维数组

NEI 也支持多维数组的定义: * 数组元素的类型如果是数组,即可表示多维数组

数据模型 - 数组 - 创建方式

* `从JSON导入` * `从接口导入`

数据模型 - 字符、数值、布尔

* 为了满足不同的开发人员的需求,NEI 可以自定义基本数据类型,比如 Objective-C 的 NSString、NSNumber 等 >自定义数据模型的使用方式和系统预置的相同 --- >等价用法:使用系统的 String,在“变量映射”中增加 `String -> NSString` 的规则

数据模型 - 文件

* 文件类型主要用在上传文件的接口中,在接口测试界面中也会有相应体现

功能:MOCK 数据

数据模型、异步接口的请求及响应参数、页面模板的参数等,系统提供了 MOCK 数据展示,优先级关系如下: >`默认值 > 生成规则 > 随机数据` --- >生成规则可以是合法的 JavaScript 脚本代码,但建议使用调用规则函数的代码,函数可以复用,管理维护也更方便 --- >枚举类型的 Mock 数据是其中的某个值

规则函数

规则函数

* 指 JavaScript 函数,定义时需要指定函数名和函数体 * 参数需要通过 `arguments` 对象获取,请参考 [arguments对象说明](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments)

规则函数 - 分类

* `生成规则`:参数的 Mock 数据 * `发送规则`:异步接口的发送前调用规则 * `接收规则`:异步接口的返回后调用规则 >不同类型的规则函数,注入的参数是不同的,请参考 [NEI平台规则函数使用说明](https://github.com/NEYouFan/nei-toolkit/blob/master/doc/NEI%E5%B9%B3%E5%8F%B0%E8%A7%84%E5%88%99%E5%87%BD%E6%95%B0%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E.md)

规则函数 - 系统预置规则

为了区别自定义的规则函数,系统预置的规则函数都挂在 `NEI` 对象下,目前共有 10 个,更多信息请参考[文档](https://github.com/NEYouFan/nei-toolkit/blob/master/doc/NEI%E5%B9%B3%E5%8F%B0%E8%A7%84%E5%88%99%E5%87%BD%E6%95%B0%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E.md): * `NEI.num()`,生成随机数字 * `NEI.url()`,生成随机URL地址 * `NEI.chinese()`,生成随机中文字符串 * `NEI.email()`,生成随机邮箱地址 * `NEI.id()`,生成唯一标识 * `NEI.str()`,生成随机字符串 * `NEI.bool()`,生成随机布尔值 * `NEI.var()`,生成随机类型的值 * `NEI.repeat()`,生成指定元素个数的数组 * `NEI.loop()`,生成指定层数的数据

异步接口

异步接口

最核心的项目资源,它包含以下信息: * 请求地址、方式 * 请求头信息 * 请求参数 * 发送规则 * 响应头 * 响应结果 * 接收规则

话题:RESTful API 设计概要

* 资源“增删改查”的标准,使用 json 通信 * 以 User 实体为例,它的“增删改查”的接口分别是: * 获取列表:`GET /users/` * 获取单个:`GET /users/:id` * 单个创建:`POST /users/` * 批量创建:`POST /users/` * 更新单个:`PATCH /users/:id` * 删除单个:`DELETE /users/:id` * 删除多个:`DELETE /users/?ids=id1,id2,...`

话题:RESTful API 设计概要

NEI 项目中的一些实践: * 统一使用复数(users),统一使用小写 * url 前面可以加限定,比如 `/api/users/` * url 中不出现动词,比如 `/deleteUser/` * DELETE 的请求体有些代理会不识别,最好放在 url 中 * 详细的操作动词放到查询参数中,比如更新 user 头像: * `PATCH /users?changeavatar`

话题:RESTful API 设计概要

使用正确的 http 响应状态码,常见的有: * `200,OK`,操作成功 * `201,OK`,创建成功 * `204,OK`,删除成功 * `400,Bad Request`,请求无效 * `401,Unauthorized`,未授权 * `405,Method Not Allowed`,方法不允许 * `500,Internal Server Error`,服务器异常

话题:RESTful API 设计概要

* NEI 默认对 RESTful API 支持良好 * 内置了常见的请求方式:GET、POST、DELETE、PUT、PATCH 等 * 数据模型有 CRUD 的功能,可以一键生成相应的“增删改查”接口

异步接口 – 请求地址、方法

* 在创建异步接口时,需要指定请求地址,比如 /users >在填写访问地址的时候,只要写相对地址即可,host 的值由环境决定,比如: * 本地 http://127.0.0.1/users * 线上 https://nei.netease.com/users/ * 请求方法一般使用系统内置的方法即可:GET、POST、DELETE、PUT、PATCH 等

异步接口 – 请求头、请求参数

* `请求头`即发送请求时添加到 Request Headers 中的参数 * `请求参数`即要发送的数据,默认是哈希对象 >JSON 共有 6 种类型:string、number、boolean、null、object、array。除了 null 之外,其他类型 NEI 都支持

异步接口 – 响应头、响应参数

* `响应头`即服务器需要返回的头信息 * `响应参数`即异步接口返回的数据

异步接口 – 响应参数定义技巧

* 响应参数的格式一般是固定的,可以定义一个通用的 ResultData 数据模型,它的结构如下所示: ```js { "code": "[number]", // 请求返回的状态码 "msg": "[string]", // 返回的信息 "result": "[variable]" // 真正的数据部分, 类型可变 } ``` * 点击“导入”按钮,选择 ResultData,然后再选择 result 的具体类型,比如它是一个数组,数组的每一项都是一个 User 对象

异步接口 – 响应参数定义技巧

某些接口返回的参数格式可能是这样的: ```json { "code": "[number]", "message": "[string]", "result": { "data": "[variable]", "total": "[number]" } } ``` 即 result 是一个对象,除了数据部分外,还包括了一些其他信息,但字段名称不确定,所以无法使用通用的格式

异步接口 – 响应参数定义技巧

* 可以使用二级参数,result 字段的类型选择为 Object >老版本的 NEI,无法很好地支持这个功能:需要给每一种响应增加一种数据模型,很繁琐,而且新增的数据模型无法复用,数据模型本身也没有意义

异步接口 – 发送、接收规则

* `发送规则`:在发送数据之前,对数据进行一些特殊处理,比如对密码进行加密等 * `接收规则`:在服务器返回数据后,对数据进行一些特殊处理后再返回给客户端脚本代码

页面

页面

* 指可以通过地址访问的普通页面,它主要包含了: * 访问地址 * 参数列表 * 模板列表 * 接口列表

页面 - 访问地址

* 和异步接口类似,也使用相对地址

页面 - 参数列表

有两种传递方式: * GET:通过 url * POST:通过 form 表单 比如,定义了参数 userId,此时页面的开发人员就知道,访问该页面的时候将会传入 userId 参数,即访问地址是:http://127.0.0.1?userId={userId} ,根据 userId 参数可以做一些相应的业务逻辑

页面 - 模板列表

* 每张页面至少有一个模板 * 模板需要模板引擎来解析生成 html,常见的模板引擎有 freemarker、velocity、ejs 等 * 创建时无需填写扩展名(.ftl、.vm、.ejs 等),扩展名在工程规范中指定 * 一张页面可以有多个模板,每个模板表示页面的某种状态,比如`成功`、`失败`等状态,服务端根据业务逻辑返回相应的模板 >如果模板没有被页面引用,则构建工具不会生成这个模板文件

页面 - 接口列表

* 只是表明该页面会用到哪些异步接口

页面模板

页面模板

* 服务端的模板文件,主要包含了: * 文件路径 * 预填数据

页面模板 - 文件路径

* 在使用构建生成模板文件时,存放的`相对于模板根目录的路径` >`模板根目录`在工程规范中设置

页面模板 - 预填数据

* 服务端 Controller 注入给模板的数据,模板引擎会根据自己的语法规则,替换掉相应的插值变量

业务分组

业务分组

* 一个项目可以有多条业务线,业务分组可以用来更好地管理资源,它是唯一的 >和标签不同:资源可以有多个标签,但只能属于一个分组

消息通知

消息通知

* 个人消息 * 系统消息 * 新版本发版,新功能上线,活动等

消息通知 - 个人消息

* 规范 * 创建的规范被他人收藏 * 收藏的规范被他人删除 * 收藏的规范被他人取消了共享

消息通知 - 个人消息

* 项目组 * 项目组被创建者删除 * 自己已加入项目组 * 自己被移出项目组 * 自己被拒绝加入项目组 * 有其他人申请加入项目组 * 有其他人已加入项目组 * 项目组被更新

消息通知 - 个人消息

* 项目 * 有人创建了项目 * 有人删除了项目 * 有人更新了项目

消息通知 - 个人消息

* 资源的新建、更新、删除,需要通知该资源的负责人 >如果负责人是操作者本身,则不用通知 --- >如果没有负责人,则不用产生通知 --- >异步接口、页面模板和数据模型,需要通知引用它的资源的负责人

接口测试

接口测试

* 根据接口定义,验证接口实现的正确性 * 填写服务器地址 * 填写请求数据 * 填写期望值和出错提示,选填 * 批量运行测试用例,方便回归 >目前会检测字段类型、期望值、字段缺失等情况,测试完成后会有详细的测试报告

接口测试 - 开发计划

* 依赖测试:前一个接口的返回作为后一个接口的输入 * 对接 JIRA:测试失败时可以提 bug 到 JIRA 系统 * 其他需求收集中...

工程规范

工程规范

* 定义了工程的初始化结构,构建工具会按照定义数据在本地生成相应的结构

工程规范 - 实现原理

![工程规范 - 实现原理](/public/nei/spec.png)

工程规范 - 和项目关联

* 在项目的“工具设置”中,可以分别指定项目的“WEB、Android、iOS 和 测试”工程规范 >工程规范也可以当做脚手架来使用

工程规范 - 变量映射规则

* 在生成代码时,可以将某种类型映射成另外一种类型,比如将所有的 `String` 映射成为 `NSString` * 可以在三个地方设置变量映射规则,优先级关系如下: >`项目 > 项目组 > 工程规范`

工程规范 - JAR 包映射规则

* 对于 Java 项目,在 ftl 模板中可以直接调用 JAR 包提供的静态方法,比如 `StringUtil.highlight()` ,此时需要建立注入模板的实例名和类名的映射关系,比如: | 实例名 | 类名 | | :--- | :--- | | `StringUtil` | `com.netease.util` |

话题:fmpp 加载 JAR 文件

有两种方法: * 在 ftl 模板通过 pp.loadData 加载: ```html <#assign Util=pp.loadData('eval', ' return new Util(); ')> ``` * 通过配置文件的 data 属性添加: ```json data: { {"Util":eval('new Util();')} } ``` > NEI 使用的是第二种方式

工程规范 - 分享

* 可以分享工程规范,对所有用户可见 >如果只想对项目组内用户可见,只要在“工具设置”中关联该工程规范即可

工程规范 – 特殊目录

* `静态资源根目录`:在使用本地模拟容器时,需要该信息,该目录用来存放静态资源 * `模板根目录`:在使用本地模拟容器时,需要该信息,该目录用来存放页面模板 * `接口MOCK数据根目录`:构建工具生成的异步接口的mock数据会放到该目录下面

工程规范 – 特殊目录

* `模板MOCK数据根目录`:使用本工具生成的页面模板的mock数据会放到该目录下面 * `JAR包根目录`:存放自定义JAR包,ftl模板可以直接调用JAR包中的静态方法

工程规范 – 特殊文件

* `接口列表填充`:每个异步接口都会生成一个文件 * `数据模型列表填充`:每个数据模型都会生成一个文件 >为了保持通用性,区分了枚举类型和非枚举类型。如果需要使用枚类型的数据类型列表,需要在文件名后面加上`!!enum` * `页面模板列表填充`:每个页面模板都会生成一个文件

工程规范 – 特殊文件

* `视图列表填充`:每个视图都会生成一个文件 * `命令行参数配置文件`:该文件的内容须为有效的 json,它的值会作为本构建工具的命令行参数 * `自定义Handlebars辅助函数`:构建工具会运行这个文件,注册自定义方法

工程规范 – 命令行参数

命令行参数的值来自三部分: * `终端输入的命令行参数`:指的是用户在命令行中输入的参数,可以是用于构建工具自身的参数,也可以是用于模板填充的数据 * `在项目中设置的命令行参数列表` * `在工程规范中指定的命令行参数文件`:文件的内容须是有效的 json。如果指定了多个这样的文件,则取第一个文件的内容

工程规范 – 命令行参数

三者的优先级关系如下: > `终端输入的命令行参数` > `在项目中设置的命令行参数` > `在工程规范中指定的命令行参数文件`

工程规范 – 模板数据

* 传给模板的数据格式说明请参考: * [传给模板的数据说明](https://github.com/NEYouFan/nei-toolkit/blob/master/doc/传给模板的数据说明.md) * Handlebars 辅助函数集说明: * [Handlebars辅助函数集](https://github.com/NEYouFan/nei-toolkit/blob/master/doc/Handlebars辅助函数集.md)

构建工具

构建工具

* 地址:[https://github.com/NEYouFan/nei-toolkit](https://github.com/NEYouFan/nei-toolkit) * 主要功能: * 根据 NEI 平台定义的工程规范,生成工程的初始化目录结构 * 自动集成在 NEI 上定义的资源:页面、异步接口、数据模型、页面模板、业务分组等 * 本地模拟容器

构建工具 - 安装

* 通过以下命令安装构建工具: >`npm install nei –g` --- >构建工具基于 Node.js 平台,安装的 Node.js 版本须为 v4.2 及以上

构建工具 - build

* 根据定义的工程规范,生成工程的初始化结构,指令: >`nei build -k [key] [参数]` --- >项目有唯一的 key,通过这个 key 可以加载项目的数据 --- >工程规范也有唯一的 key,参数为 `sk`

构建工具 - update

* 更新通过 nei build 构建的项目,指令: >`nei update [参数]` --- >可以先在本地创建项目目录,然后在该目录下使用 `nei build` 和 `nei update` 命令,使用默认值即可

构建工具 - server

* 启动内置的本地模拟容器,指令: >`nei server [参数]` --- >本地模拟容器会 Mock 定义好的异步接口和页面,也会返回按照定义生成的 Mock 数据,从而使得前后端并行开发成为可能,更多信息请参考:[使用 NEI 进行前后端并行开发](https://github.com/NEYouFan/nei-toolkit/blob/master/doc/%E4%BD%BF%E7%94%A8NEI%E8%BF%9B%E8%A1%8C%E5%89%8D%E5%90%8E%E7%AB%AF%E5%B9%B6%E8%A1%8C%E5%BC%80%E5%8F%91.md)

构建工具 - server.config.js

* 根据工程规范的设置生成的配置文件,一般不用更改 >配置参数的含义请参考注释说明

构建工具 - server.config.js - routes

示例: ```js routes: { //"ALL /api/*": "代理所有接口, 这里输入代理服务器地址", "GET /user/profile/:id": { name: 'mypage', index: 0, list: [{"id":10686,"path":"page/test"},{"id":10758,"path":"error"}] }, "POST /api/category/add": { path: 'post/api/category/add/data', id: 14077 }, "GET /api/category": { path: 'get/api/category/data', id: 14413 }, "POST /api/category": { path: 'post/api/category/data', id: 14076 }, "GET /api/author": { path: 'get/api/author/data', id: 14072 }, } ```

构建工具 - server.config.js - routes

>打开 `"ALL /api/*"` 可以将所有的接口代理到同一个地址,方便在不同的环境间进行切换 --- >有 `list` 的表示是页面,值是页面模板列表,显示哪个模板由 `index` 的值决定

构建工具 - template

* 解析本地模板,并生成新文件,指令: >`nei template [参数]` --- >模板解析引擎是 Handlebars

本文档在线访问地址

[http://gzool.com/nei](http://gzool.com/nei)

Thank You

Q & A

[包勇明](https://github.com/huntbao) / [@huntbao](http://weibo.com/gzooler)