版本需求: java17
当前版本:1.6.0
模拟API响应的服务端,只需要简单配置就能模拟真实API。
上班,联调、测试。
本地连不上!
接口要等发版?
连不上!!
本服务启动迅速,配置简单,模拟真实,并且独立于原项目。
拒绝API焦虑,再也不担心接口调不通无法开发辣。
详细使用说明见内置文档页 doc.html,
架构与实现细节见 doc/Mock Api 技术设计方案.md。
- 配置简单
- 支持脚本语言 JS、QLExpress
- 安全调用(脚本沙箱、资源路径限制、可关闭登录校验)
- 支持RESTful格式路径:如:
/demo/{user}/{id} - 支持所有springboot支持的请求类型
- 支持完全自定义响应(状态码、响应头、响应体甚至是文件响应)
- 静态资源展示
- 跨域调用开关
- 文件变化自动重载
- MockJs模版响应
- 支持多模块动态切换
- 内置可视化页面
- 在线可视化编辑:响应组/处理器配置表单编辑、脚本与文本资源编辑器(补全、格式化、常用快捷键)
- 模版化新建与上传:重定向、文件下载等内置模版,支持上传已有资源文件
- 调试与共享变量:查看运行期信息,在线查看/设置各级共享变量
- 后台登陆验证
启动脚本中的
webNeedLogin改为false即刻免登陆使用
- GraalJs - Javascript(ES14)
- QLExpress - 类java语法(阿里开源的脚本引擎)
本项目基于Springboot框架编写,Java版本为JDK17。
下载最新的release版本并解压,或自行构建(见 构建与开发)。
windows使用startMock.bat启动
linux使用startMock.sh启动
两个脚本实际执行的都是:
java -jar -Dpolyglot.engine.WarnInterpreterOnly=false -Dmock.webNeedLogin=true mock.jar好,你已经启动了一个由示例模块驱动的Mock服务。
访问此路径,开始你的Mock之旅。
http://localhost:8990/mock/static/index.html
- 如果data目录不存在会创建data目录,并创建示例模块example(仅当使用默认数据目录
./data时生效,可用mock.generateExampleModule=false关闭) - 开启登录校验时会生成一个默认的账号密码,存储在
./data/global-mock.yml文件中(默认用户名admin,密码为16位随机口令,仅在启动日志打印一次)
在模块页面可以管理当前激活的模块,每个模块的API相互独立。
在注册表页面可以查看当前已注册的地址
在响应组页面可以查看并在线编辑响应组配置、脚本与文本资源(详见响应组可视化编辑)
在调试页面可以查看节点与运行期信息,并在线查看/设置共享变量
在实时事件页面会展示系统内监控事件的触发情况
在模块页面可以管理模块(激活切换、配置、新建、重命名)并手动重新加载Mock
在文档页(doc.html)可以快捷查看使用文档
data里随便建一个文件夹,在这个文件夹里放几个json启动也能行。
- mock
- data
- example
- a.b.c.json
- a.b.c..json.json
- user.info.js
- example
- static
- ...
- mock.jar
- data
默认会把文件名里的.替换为/并省略后缀。
例:a.b.c.json,访问路径是a/b/c,什么方法都行。
例2:a.b.c..json.json,访问路径是a/b/c.json,俩点会被换成一个点。
{
"code": "0",
"msg": "success!"
}例3:user.info.js,访问路径是user/info,JS脚本,请求响应工具见脚本使用。
return {
code: 0,
msg: 'success!'
}http://localhost:8990/a/b/c
http://localhost:8990/a/b/c.json
http://localhost:8990/user/infodata/example 由服务从内置资源生成,可以直接体验各类能力:
| 文件 | 访问路径 | 说明 |
|---|---|---|
example/info.yml |
/example/info |
配置继承演示,响应体中使用 ${envMsg} 环境变量 |
example/redirect.yml |
/example/redirect |
302 重定向 |
example/mixfile/JS方法示例-绝对路径.js |
/function/example/{id} |
function main() 写法,走 MockJs 模板 |
example/mixfile/角色列表-相对路径.js |
/example/mixfile/角色列表-相对路径 |
({...}) 写法,自动走 MockJs |
example/mixfile/角色信息-相对路径.yml |
/example/mixfile/get/{id} |
相对路径 + 请求方法限制 |
example/group-mock.yml把模块根路径设置为/example,因此示例接口都带该前缀。
多模块共享的静态资源可以放到static文件夹里
- mock
- data
- ...
- static
- ...
- mock.jar
- data
内置页面的静态资源固定在
/mock/static/**(classpath 内),不会暴露进程工作目录下的文件。
运行目录生成的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}
快访问试试罢。
脚本文件以
({起始、以})结束时自动按 MockJs 模板处理; 也可以写成function main(){ ... }或立即执行函数形式,详见脚本使用。
# 1. 静态文件响应(文件下载)
request:
path: "/file/download"
response:
processType: File
filePath: "./example.txt"
downloadFileName: "示例文件.txt"
fileContentTypeAuto: true# 2. 302 重定向
request:
path: "/redirect/github"
response:
processType: Redirect302
body: "https://github.com/chenxuan353"# 3. 允许跨域
request:
path: "/cors/demo"
cors: true# 4. 静态资源模式(整个目录当静态资源访问)
request:
path: "/static-demo"
staticMode: true项目地址:https://github.com/oracle/graaljs
GraalJS 是 Oracle 开源的一种基于 GraalVM 构建的快速 JavaScript 语言实现。
对可使用的java类进行了限制(默认安全模式,且始终禁止脚本读写文件、创建线程/进程与加载宿主类)
性能说明:GraalJs 引擎与内置库的首次编译需要约 2 秒。服务启动完成后会在后台线程自动预热,
启动日志会输出 GraalJs 引擎预热完成,耗时:xxxms,因此首个 JS 请求不再承担该初始化开销
(实测首个 JS 请求由约 2.1s 降至约 0.3s)。
内置 Mock.js 改为按需加载:仅当脚本中出现 Mock(Mock.mock、Mock.Random 等)或使用
({ ... }) 的 MockJs 对象写法时才载入,未使用 Mock 的脚本每次请求可省去整库的编译执行开销。
需要 Mock 时直接使用全局 Mock 即可;通过配置(response.jsLoadAxios: true)可再载入内置的Axios.js。
可用全局对象:Mock(按需加载)、axios(可选)、console(代理到服务日志)、requestJson(请求体 JSON 解析结果)。
项目地址: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- 模块配置(名称、描述,同时作为根响应组配置的基底)group-mock.yml- 根响应组配置(优先级高于module-mock.yml)- 响应组A
group-mock.yml- 响应组配置- 响应组A
- 响应组...
- 响应组N
- 请求处理器文件组
- ...
- 响应组B
- ...
- 响应组N
- 请求处理器文件组A - 由文件名相同的文件构成文件组
- 请求处理器文件组...
- 请求处理器文件组N
- 模块B
- ...
可写在 application.yml、启动参数(-Dmock.xxx=yyy)或运行目录的 config/mock.yml 中。
| 配置项 | 默认值 | 说明 |
|---|---|---|
mock.webNeedLogin |
true |
管理接口是否需要登录 |
mock.dataPath |
./data |
数据目录;改为非默认路径时必须已存在 |
mock.activeModule |
无 | 默认激活模块(被 global-mock.yml 中的配置覆盖) |
mock.generateExampleModule |
true |
首次创建数据目录时生成示例模块 |
mock.autoSaveActiveModule |
true |
切换模块时回写 global-mock.yml |
mock.staticModeLoadFiles |
true |
静态模式响应组是否加载文件列表 |
mock.enableEngineList |
[GraalJs, QLExpress] |
启用的脚本引擎 |
mock.enableDirWatch |
true |
是否监听数据目录变化 |
mock.dirWatchCheckInterval |
1000 |
变化检测间隔(毫秒,需 > 15) |
mock.dirWatchCheckMaxCount |
3 |
连续无变化的检查次数达到该值才重载 |
mock.allowExternalResourcePath |
false |
是否允许引用数据目录之外的资源文件 |
mock.versionPath |
./versions |
资源编辑历史版本目录(同一节点最多 5 个、目录内最多 30 个) |
mock.jsEngine.* / mock.qleEngine.* |
见下 | 引擎开关 |
引擎开关(jsEngine 与 qleEngine 同名同义):
| 配置项 | 默认值 | 说明 |
|---|---|---|
secureMode |
true |
安全(沙箱)模式 |
exportRequest / exportResponse |
false |
是否向脚本暴露原生 request / response |
exportSafeSession |
true |
会话读写是否校验数据类型 |
exportShareVar / exportParentShareVar / exportGlobalShareVar |
true |
是否暴露各级共享变量 |
jsEngine.useConsoleLog |
false |
是否放行脚本控制台输出(默认代理到服务日志) |
qleEngine.runningTimeLimit |
10000 |
QLExpress 执行时间上限(毫秒) |
运行状态与调试页的请求统计全部保存在内存中,可通过下列配置调整或整体关闭:
| 配置项 | 默认值 | 说明 |
|---|---|---|
mock.metrics.enable |
true |
是否启用请求统计;关闭后不再记录任何统计信息,状态页只展示运行期信息 |
mock.metrics.realtimeRetainSeconds |
3600 |
实时明细保留时长(秒),超出该时长的记录不再计入趋势与分布图表 |
mock.metrics.realtimeMaxRecords |
10000 |
实时明细最大条数,写满后覆盖最旧的记录(可累计的计数不受该上限影响) |
mock.metrics.includeManageRequest |
false |
是否把管理接口与内置页面(/mock/ 前缀)的请求一并统计 |
统计写入路径只做原子自增与一次环形槽位替换,不加锁、不做复杂计算; 服务启动后可在运行状态页点击「重置统计」清零全部计数与实时明细。
| 配置项 | 默认值 | 说明 |
|---|---|---|
request.log.onlyProcessLog |
true |
是否只记录命中 Mock 处理器的请求(false 时记录全部请求) |
request.log.bodyLimit |
1048576(1MB) |
请求体缓存上限,同时作为请求体/响应体日志正文的截断长度 |
请求体超过
bodyLimit后不再继续缓存,日志与实时事件只保留已缓存的部分并标注截断信息, 请求本身仍会被完整读取并正常处理。
响应组编辑器通过页面上传资源文件时受 Spring 的文件上传限制约束:
| 配置项 | 默认值 | 说明 |
|---|---|---|
spring.servlet.multipart.max-file-size |
32MB |
单个上传文件上限 |
spring.servlet.multipart.max-request-size |
128MB |
单次上传请求总大小上限 |
超出限制时接口返回
M00008(上传文件不合法),可在application.yml或启动参数中调整。
activeModule: example
username: admin
password: "******"模块名就是文件夹名(也可填写模块的显示名)。
适用于group-mock.yml以及请求处理器文件组.yml(module-mock.yml 只取 name/des)。
注意:配置文件中的
request与response选项组会自顶向下继承子级非空字段会覆盖父级对应值(
response.headers等 Map 字段是整体替换)
log配置就近生效:本节点未配置时向上取第一个有配置的节点
name: 名称
des: 描述
# 是否启用
# enable: true
request:
# 请求映射路径,支持相对路径或绝对路径(以`/`起始时忽略上级路径配置)
# 默认取父路径/文件名路径(`.`替换为`/`,`..`替换为`.`)
path: "example/get/{id}"
# 请求允许的方法 默认允许所有方法
methods:
- POST
# 限制请求头
# headers:
# - Content-Type=application/json
# 限制请求参数
# params:
# - version=v1
# 限制请求类型与响应类型
# consumes:
# - application/json
# produces:
# - application/json
# 允许跨域(允许所有)
# cors: true
# 关闭路径转换(`.`->`/`)
# disablePathConvert: 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、css、xml
单文件组、自动保留路径后缀同时视为静态类型的文件
jpeg、jpg、png、mp4、gif、mp3、css、svg、xml、zip、rar、bmp、ttf
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 / pathVar | 路径变量字典 |
| headers | 请求头字典(键名大小写不敏感) |
| envionment / environment | 环境变量字典(envionment,只读,无法在脚本中修改) |
| resources | 资源字典,包含内部与externalTextResources定义的外部文本资源 |
| externalFileResources | 支持的外部文件键名字典(externalFileResources,仅键名列表) |
| requestBody | 请求体字符串 |
| requestJson | 请求体 JSON 解析结果(仅 JS 引擎,解析失败为 null) |
| requestJsonParseError | 请求体 JSON 解析失败原因(仅 JS 引擎) |
| logger / log | 日志对象 |
| session | session对象(会话内容读写助手,不暴露原生 Session) |
| respHelper | 响应帮助类,用于设置响应 |
| JsonHelper | Json帮助类 |
| shareVar | 执行器共享变量对象 |
| parentShareVar | 父响应组共享变量对象 |
| globalShareVar | 全局共享变量对象 |
request、response默认不导出,需要时通过mock.jsEngine.exportRequest/mock.jsEngine.exportResponse(QLE 为mock.qleEngine.*)开启。
paramspathVariableresourcesheaders
| 方法签名 | 描述 |
|---|---|
| get(String key) | params.get("id") |
var id = params.get("id");用于日志输出(log 是它的别名)
| 方法签名 | 描述 |
|---|---|
| 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) | 设置响应体(非字符串自动转 JSON;body(null) 可清空) |
| 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) | 设置响应头 |
| badRequest() / notFound() / internalServerError() | 快捷设置 400 / 404 / 500 状态码 |
| redirect(String path) | 302重定向(保留已设置的响应头,之后 code/body 不再生效) |
| int getCode() | 获取当前设置的状态码 |
| String getBody() | 获取当前设置的响应体 |
| String getFileKey() | 获取当前设置的文件响应键 |
| Map<String, String> getHeaders() | 获取当前设置的响应头 |
| String getHeader(String header) | 获取当前设置的响应头 |
| boolean isFileDownload() | 是否已标记为文件下载 |
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) | 设置共享变量(值为 null 时等同于移除) |
| void remove(String key) | 移除某个键 |
| void rm(String key) | 同上void remove(String key) |
| void delete(String key) / del(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)processType 为 TextTemplate、JSONTemplate 或 MockJsStr 时,响应体会做一次 ${} 替换:
| 写法 | 取值 |
|---|---|
${envMsg} / ${envionment.envMsg} |
环境变量 |
${headers.User-Agent} |
请求头 |
${id} / ${pathVariable.id} / ${pathVar.id} |
路径变量 |
${q} / ${parameterMap.q} |
单值请求参数 |
${q[0]} / ${parameterMap.q[0]} |
多值请求参数(不提供裸键) |
- 单个文本资源(脚本、模板、外部文本资源)超过 15MB 会被跳过;
- 请求体与响应体的日志正文按 1MB 截断(可通过
request.log.bodyLimit调整),超限只影响日志记录,不影响请求处理与响应返回; - 资源文件默认必须位于数据目录内,越界会被拒绝(
mock.allowExternalResourcePath=true可放开); - 脚本默认不允许读写文件、创建线程/进程、加载宿主类。
| 值 | 描述 |
|---|---|
| JS | JS脚本(同 GraalJs、Javascript) |
| GraalJs | JS脚本 |
| Javascript | JS脚本 |
| QLExpress | QLE脚本 |
| MockJsStr | Mock模版(JSON 模板须为严格 JSON) |
| TextTemplate | 文本模版(做 ${} 替换) |
| Text | 文本(不做替换) |
| JSONTemplate | JSON模版,与文本模版相同 |
| JSON | JSON 文本(不做替换) |
| Html | HTML 文本 |
| Xml | XML 文本 |
| CSS | CSS 文本 |
| JS_Resource | 以文本返回 JS 文件内容 |
| StaticFile | 静态资源 |
| File | 文件,下载或展示 |
| Redirect302 | 请求重定向 |
response:
processType: JS通常不需要配置
processType:服务会按脚本后缀与文件组内的资源自动推断,推断不出则按文本模版处理。
| 错误码 | HTTP | 含义 |
|---|---|---|
M00001 / M00002 |
404 | 不存在已激活模块 / 模块不存在 |
MP00001 |
500 | 响应执行器异常 |
MP00002 |
500 | 响应处理器运行时异常(脚本异常) |
MP00003 |
400 | 处理类型识别失败 |
MP00004 |
404 | 未找到可供运行的响应处理器 |
MP00005 / MP00006 |
400 | 静态文件处理器文件数不为 1 / File 类型缺少 filePath |
MP00007 |
404 | 文件不存在 |
MP00008 / MP00009 |
400 | 重定向缺少响应体 / 重定向路径不合法 |
MP00010 |
401 | 未登录或登录过期 |
MP00011 / MP00012 |
401 | 登录失败 / 账户信息校验失败 |
# 构建(产物 target/mock.jar)
mvn -B clean package -DskipTests
# 运行
java -jar target/mock.jar- Windows 下可使用仓库自带的
mvnw.cmd,Linux/macOS 使用./mvnw。 - 免登录调试:追加
-Dmock.webNeedLogin=false。 - 使用独立数据目录:追加
-Dmock.dataPath=<绝对路径>(目录需已存在)。 - 测试:
mvn test(src/test/java下包含 YAML 读写相关用例)。 - 内置页面的第三方前端库(Vue、Element UI、axios、CodeMirror、js-beautify)全部离线存放于
src/main/resources/static/vendor/,升级或替换请同步更新该目录下的README.md。
内置页面在脚本加载期间显示统一的「加载中…」动画(
js/app-loading.js):[v-cloak] { display: none !important }保证 Vue 未挂载前模板不可见,挂载完成后自动移除动画; 若页面脚本加载失败,会在 3 秒后兜底移除v-cloak并撤下动画,避免页面永久空白。
仓库提供 Dockerfile 与 docker.sh:
docker build -t java/mock-api .
docker run -p 8990:8990 --name mock-api -e TZ="Asia/Shanghai" -d java/mock-api
Dockerfile中的 jar 文件名需与实际构建产物(mock.jar)保持一致,使用前请按需调整。
基于 MIT 许可发布,详见 LICENSE。



