版本需求: java17
模拟API响应的服务端,只需要简单配置就能模拟真实API。
上班,联调、测试。
本地连不上啊!
什么?接口要等发版?
啊啊?这个环境连不上吗!!
这种事情不要啊。
早点下班吧,我的朋友!
本服务启动迅速,配置简单,模拟真实,并且独立于原项目。
拒绝API焦虑,做回自由的自己。
再也不用担心接口调不通无法开发辣。
- 配置简单
- 支持脚本语言 JS、QLExpress
- 安全调用
- 支持RESTful格式路径:如: /demo/{user}/{id}
- 支持所有springboot支持的请求类型
- 支持完全自定义响应(状态码、响应头、响应体甚至是文件响应)
- 静态资源展示
- 跨域调用开关
- 文件变化自动重载
- MockJs模版响应
- 支持多模块动态切换
- 内置可视化页面
- GraalJs - Javascript(ES14)
- QLExpress - 类java语法(阿里开源的脚本引擎)
本项目基于Springboot框架编写,Java版本为JDK17。
下载最新的release版本。
下载示例数据文件夹data,放置于数据文件夹中。
java -jar mock.jar好,你已经启动了一个由示例模块驱动的Mock服务。
访问此路径,开始你的Mock之旅。
http://localhost:8990/static/index.html
首次启动时会生成一个默认的账号密码,存储在./data/global-mock.yml文件中。
data里随便建一个文件夹,在这个文件夹里放几个json启动也能行。
默认会把文件名里的.替换为/并省略后缀。
例:a.b.c.json,访问路径是a/b/c,什么方法都行。
例2:a.b.c..json.json,访问路径是a/b/c.json,俩点会被换成一个点。
例3:a.b.c.js,访问路径是a/b/c,JS脚本,有个return返回就行,请求响应工具见脚本使用。
你就说快不快吧
可以查看模块信息,进行简单的配置以及查看。
http://localhost:8990/mock/static/index.html
多模块共享的静态资源可以放到static文件夹里
- mock
- data
- ...
- static
- ...
- mock.jar
- data
运行目录生成的data目录下创建文件
login.info.json
{
"code": "0",
"msg": "OK!",
"data": {
"loginUser": "chenxuan353",
"loginRole": ["Admin", "User"]
}
}访问看看效果吧
http://localhost:8990/login/info
还是在data目录下创建文件
get.{id}.js
({
id: pathVariable.get('id'),
"name": "@cname",
"des|1-10": "★",
"birthday":'@date("yyyy-MM-dd")',
"msg": "当JS文件以`({`起始`)}`结束时,会自动进行Mock处理。否则视为JS文件运行。"
})del.{id}.js
id = pathVariable.get('id');
if (id in [1, 2, 10, 15]) {
return {
"code": 0,
"msg": "删除成功",
"des": "这下成功了,[1,2,10,15]都能触发成功。"
};
}
return {
"code": 404,
"msg": "用户不存在",
"des": "这是模拟JS脚本动态处理,试试 /user/del/1"
};OK,现在创建了两个基于JS脚本的模拟API。
http://localhost:8990/get/{id}
http://localhost:8990/del/{id}
快访问试试罢。
项目地址:https://github.com/oracle/graaljs
GraalJS 是 Oracle 开源的一种基于 GraalVM 构建的快速 JavaScript 语言实现。
对可使用的java类进行了限制
默认载入Mock.js,支持通过配置载入内置的Axios.js。
项目地址:https://github.com/alibaba/QLExpress
阿里开源规则引擎
对可使用的java类进行了限制,类Java语法
- 不支持try{}catch{}
- 注释目前只支持 /** **/,不支持单行注释 //
- 不支持java8的lambda表达式
- 不支持for循环集合操作for (Item item : list)
- 弱类型语言,请不要定义类型声明,更不要用Template(Map<String, List>之类的)
- array的声明不一样 (array = [])
- min,max,round,print,println,like,in 都是系统默认函数的关键字,请不要作为变量名
list = new List();
list.add("1");
for(i = 0; i < list.size(); i++){
item = list.get(i);
}
所有配置文件均存在默认值,可以不提供。
global-mock.yml- 全局设置- 模块A
module-mock.yml- 模块配置- 响应组A
group-mock.yml- 响应组配置- 响应组A
- 响应组...
- 响应组N
- 请求处理器文件组
- ...
- 响应组B
- ...
- 响应组N
- 请求处理器文件组A - 由文件名相同的文件构成文件组
- 请求处理器文件组...
- 请求处理器文件组N
- 模块B
- ...
目前只有默认激活模块的配置,模块名就是文件夹名。
activeModule: example适用于module-mock.yml、group-mock.yml以及请求处理器文件组.yml
注意:配置文件中的
request与response选项组会自顶向下继承
response.headers与response.externalTextResources会合并内部配置其他数据均在子配置后替换父配置对应值。
name: 名称
des: 描述
# 是否启用
# enable: true
request:
# 请求映射路径,支持相对路径或绝对路径
# 默认取父路径/文件名路径(`.`替换为`/`,`..`替换为`.`)
path: "example/get/{id}"
# 请求允许的方法 默认允许所有方法
methods:
- POST
# 限制请求头
# headers:
# - Content-Type=application/json
# 限制请求参数
# params:
# - version=v1
# 允许跨域(允许所有)
# cors: true
# 静态文件模式(仅用于响应组,将该响应组的文件夹与文件视为静态资源)
# staticMode: true
response:
# 响应类型(默认自动识别)
contentType: application/json
# 响应头
headers:
RTP: 2333
# 响应体
body: |
{
"code": 100,
"msg": "${envMsg}"
}
# 环境变量设置
envionment:
envMsg: "默认响应体"
# 脚本路径
# scriptPath: "../example.get.{id}.js"
# 脚本内容(可以在yml中编写简单脚本)
# scriptContent: "...."
# 处理类型
# processType: JS
# 是否加载Axios异步请求库(仅适用于 processType=JS)
# jsLoadAxios: true
# 脚本外部文本资源,自动读取至环境变量(相对当前路径或模块根路径)
# 脚本或者外部文本资源的数据大小超过15mb时将跳过读取
# externalTextResources:
# data: "./example.txt"
# 脚本外部文件资源(只有该列表中的文件允许在脚本响应中以文件形式返回)
# externalFileResources:
# data: "./example.txt"
# 文件路径(仅适用于 processType=File)
# filePath: "./example.txt"
# 下载文件名(仅适用于 processType=File)
# downloadFileName: "example.txt"
# 响应类型自适应 (仅适用于 processType=File)
# fileContentTypeAuto: true
支持的processType类型
log:
# 是否启用
enable: false
# 打印执行时间
printProcessTime: false
# 请求输出总开关
printRequest: true
# 打印请求体
printRequestBody: true
# 打印请求头
printHeaders: true
# 打印路径参数
printUriVars: true
# 打印请求参数
printParam: true
# 打印Session(需配置`printSessionKey`)
printSession: true
# 打印哪些SessionKey
# printSessionKey:
# - Content-Type
# 响应输出总开关
printResponse: true
# 打印响应头
printResponseHeaders: true
# 打印响应体
printResponseBody: true模块的默认访问路径从根路径/起始。
由一个或多个请求处理器与响应组组成。
文件夹会递归解析为子响应组,支持的文件则会解析为请求处理器文件组。
响应组的组基础路径是相对模块根路径的相对路径。
例如路径
./data/module/group1/group2
group2文件夹的默认路径配置为group2,完整路径为/group1/group2
group2文件夹中的info.js文件,其关联的完整路径为/group1/group2/info
请求处理的最小单元
响应组下的同名文件将被划为一个文件组。
一个文件组就是一个请求处理器。
yml、yaml、js、qle、text、json、html、data、htm、txt、body
单文件组、自动保留路径后缀同时视为静态类型的文件
jpeg、jpg、png、mp4、gif、mp3、css、svg、css、xml、zip、rar、bmp
yml与yaml被视为该请求处理器的配置
qle视为QLExpress脚本文件,通过QLExpress解析执行。
js视为GraalJs脚本文件,通过GraalJs解析执行。
user.get.{id}.ymluser.get.{id}.jsuser.get.{id}.bodyuser.file.jsonuser.file.mp4demo.des.txtimgs.logo.pngimgs.logo.jpegfile.other.zip
不支持的文件会被忽略。
user.get.{id}user.get.{id}.yml- 被视为user.get.{id}请求处理器的配置user.get.{id}.jsuser.get.{id}.body
user.fileuser.file.json
demo.des.txt- 静态文件单独成组demo.des.txt
imgs.logo..pngimgs.logo.png
imgs.logo..jpegimgs.logo.jpeg
静态文件可以通过
response.externalFileResources配置项引入
| 变量名 | 描述 |
|---|---|
| params | get或post参数字典 |
| pathVariable | 路径变量字典 |
| headers | 请求头字典 |
| envionment | 环境变量字典(envionment) |
| resources | 资源字典,包含内部与externalTextResources定义的外部文本资源 |
| externalFileResources | 支持的外部文件键名字典(externalFileResources) |
| requestBody | 请求体字符串 |
| logger | 日志对象 |
| session | session对象 |
| respHelper | 响应帮助类,用于设置响应 |
| JsonHelper | Json帮助类 |
| shareVar | 执行器共享变量对象 |
| parentShareVar | 父响应组共享变量对象 |
| globalShareVar | 全局共享变量对象 |
paramspathVariableresourcesheaders
| 方法签名 | 描述 |
|---|---|
| get(String key) | params.get("id") |
var id = params.get("id");用于日志输出
| 方法签名 | 描述 |
|---|---|
| void debug(String var1, Object... var2) | 打印debug日志,logger.debug("日志 key={}", "key") |
| void info(String var1, Object... var2) | 打印info日志 |
| void warn(String var1, Object... var2) | 打印warn日志 |
| void error(String var1, Object... var2) | 打印error日志 |
logger.debug("日志 key={}", "key");| 方法签名 | 描述 |
|---|---|
| long getCreationTime() | 创建时间戳 |
| String getId() | 获取SessionId |
| long getLastAccessedTime() | 上次请求时间戳 |
| void setMaxInactiveInterval(int i) | 设置当前会话的失效时间,单位秒 |
| int getMaxInactiveInterval() | 获取当前会话的失效时间,单位秒 |
| Object getAttribute(String var1) | 读取session属性 |
| List<String> getAttributeNames() | 获取属性列表 |
| void setAttribute(String s, Object o) | 设置session属性 |
| void removeAttribute(String s) | 移除session属性 |
| void invalidate() | 失效会话 |
| boolean isNew() | 是否是新建会话 |
注意,只能设置属性值为基本数据类型、HashMap、ArrayList、HashSet等有限类型。
session.setAttribute("key", "xxx");
session.getAttribute("key");未注明返回值的方法返回值是其响应帮助类本身
| 方法签名 | 描述 |
|---|---|
| code(int code) | 设置响应状态码 |
| contentType(String contentType) | 设置响应类型 |
| body(Object body) | 设置响应体 |
| file(String fileKey) | 设置文件响应,fileKey需要是配置中externalFileResources的键名 |
| fileKey(String fileKey) | 同file(String fileKey) |
| download(String fileKey) | 自动设置文件下载响应,其他同file(String fileKey) |
| headers(Map<String, ?> headers) | 批量设置响应头 |
| header(String header, String value) | 设置响应头 |
| redirect(String path) | 302重定向 |
| int getCode() | 获取当前设置的状态码 |
| String getBody() | 获取当前设置的响应体 |
| String getFileKey() | 获取当前设置的文件响应键 |
| Map<String, String> getHeaders() | 获取当前设置的响应头 |
| String getHeader(String header) | 获取当前设置的响应头 |
respHelper
.code(200)
.body({code: 0, msg: "success!"})
.contentType("application/json")用于Json相关转换
| 方法签名 | 描述 |
|---|---|
| String toJsonString(Object obj) | 转换为Json字符串 |
| <T> T parse(String json, Class<T> clazz) | 从Json字符串解析 |
logger.info("JSON: {}", JsonHelper.toJsonString({key: "value"}))shareVar、parentShareVar以及globalShareVar
| 方法签名 | 描述 |
|---|---|
| Object get(String key) | 读取共享变量 |
| void set(String key, Object value) | 设置共享变量 |
| void remove(String key) | 移除某个键 |
| void rm(String key) | 同上void remove(String key) |
| int size() | 共享变量数量 |
| int length() | 同上 |
| void clear() | 清空共享变量 |
| List<String> keys() | 共享变量键列表 |
| List<Object> values() | 共享变量值列表 |
注意,只能设置属性值为基本数据类型、HashMap、ArrayList、HashSet等有限类型。
globalShareVar.set("loginStatus", true)| 值 | 描述 |
|---|---|
| JS | JS脚本 |
| QLExpress | QLE脚本 |
| MockJsStr | Mock模版 |
| TextTemplate | 文本模版 |
| JSONTemplate | JSON模版,与文本模版相同 |
| StaticFile | 静态资源 |
| File | 文件,下载或展示 |
| Redirect302 | 请求重定向 |
processType: JS