微前端平台后端服务(Spring Boot 2.7 / Java 8 / SQLite)。本文档列出当前全部 HTTP 接口、鉴权要求与示例。
http://<host>:8080application/json统一错误响应格式:
{ "code": "ERROR_CODE", "message": "错误描述" }
| 级别 | 说明 |
|---|---|
| 免鉴权 | 无需 Token,见各接口标注"免鉴权" |
| 登录态 | 请求头携带 Authorization: Bearer <token> 即可 |
| 角色 | 需 @RequireRole,如 ADMIN |
| 权限点 | 需 @RequirePermission,如 user:list |
角色/权限随 JWT 下发,修改角色或权限后需重新登录 获取新 Token 生效。
默认管理员:admin / admin123(由 sql/init.sql 一次性灌入)。
免鉴权。连通性验证。
响应 200
{ "message": "Hello from backend", "serverTime": "2026-09-22T14:00:00" }
免鉴权。当前数据源信息与健康检查。
响应 200
{ "type": "sqlite", "ping": true, "serverNow": "2026-09-22 14:00:00" }
登录态。查询演示用户列表(表 demo_user)。
响应 200
[
{ "id": 1, "name": "Alice", "created_at": "2026-09-22 14:00:00" }
]
登录态。新增演示用户。
请求体
{ "name": "Alice" }
响应 200
{ "affected": 1, "name": "Alice" }
登录态。批量新增演示用户。
查询参数:prefix(String,前缀)、count(int,数量)
响应 200
{ "affected": 100 }
免鉴权。注册,默认分配 USER 角色。
请求体
{ "username": "alice", "password": "123456", "nickname": "爱丽丝" }
响应 200(失败:USER_EXISTS 用户名已存在 / BAD_REQUEST 参数不合法)
{
"token": "eyJhbGciOiJIUzI1NiJ9...",
"tokenType": "Bearer",
"expiresIn": 7200,
"id": 2,
"username": "alice",
"nickname": "爱丽丝",
"roles": ["USER"],
"permissions": []
}
免鉴权。登录。
请求体
{ "username": "admin", "password": "admin123" }
响应 200(失败:BAD_CREDENTIALS 账号或密码错误 / USER_DISABLED 账号禁用)
{
"token": "eyJhbGciOiJIUzI1NiJ9...",
"tokenType": "Bearer",
"expiresIn": 7200,
"id": 1,
"username": "admin",
"nickname": "管理员",
"roles": ["ADMIN"],
"permissions": ["user:list", "user:create", "role:assign", "..."]
}
登录态(@RequireAuth)。返回当前登录用户信息。
响应 200(未登录:401 {"code":"UNAUTHORIZED","message":"请先登录"})
{ "id": 1, "username": "admin", "nickname": "管理员", "roles": ["ADMIN"], "permissions": ["..."] }
以下接口均需
ADMIN角色;权限收回时返回 403{"code":"FORBIDDEN","message":"无角色权限"}或无操作权限。
权限点:role:list。角色列表(含用户数)。
响应 200
[
{ "id": 1, "code": "ADMIN", "name": "超级管理员", "description": null, "created_at": "...", "user_count": 1 }
]
权限点:role:create。创建角色。
请求体
{ "code": "EDITOR", "name": "编辑", "description": "内容编辑" }
响应 200(ROLE_EXISTS:编码已存在)
权限点:role:update。更新角色名称/描述。
请求体
{ "name": "资深编辑", "description": "..." }
响应 200(NOT_FOUND:角色不存在)
权限点:role:delete。删除角色(级联清理关联关系)。
响应 200 { "deleted": 3 }
权限点:role:assign。查询角色拥有的权限列表。
响应 200
{
"role": { "id": 1, "code": "ADMIN", "name": "超级管理员" },
"permissions": [ { "id": 1, "code": "user:list", "name": "user:list" } ]
}
权限点:role:assign。覆盖式设置角色拥有的权限。
请求体
{ "ids": [1, 2, 3] }
响应 200:同 GET /api/rbac/roles/{id}/permissions
权限点:permission:list。权限点列表。
响应 200
[
{ "id": 1, "code": "user:list", "name": "user:list", "description": null, "created_at": "..." }
]
权限点:permission:create。新增权限点。
请求体
{ "code": "report:export", "name": "导出报表", "description": "..." }
响应 200(PERMISSION_EXISTS:编码已存在)
权限点:permission:delete。删除权限点(级联清理关联关系)。
响应 200 { "deleted": 5 }
权限点:role:assign。覆盖式设置用户拥有的角色。
请求体
{ "ids": [1, 2] }
响应 200:同 GET /api/rbac/users/{id}/auth
权限点:role:assign。查询用户的角色与权限。
响应 200
{
"userId": 2,
"roles": [ { "id": 2, "code": "USER", "name": "普通用户" } ],
"permissions": [ { "id": 6, "code": "data:query", "name": "data:query" } ]
}
登录态。当前登录用户的角色与权限(同 /api/auth/me 的 roles/permissions,从库中实时查)。
响应 200
{
"userId": 1,
"roles": [ { "id": 1, "code": "ADMIN", "name": "超级管理员" } ],
"permissions": [ "..." ]
}
以下接口均需
ADMIN角色;@RequirePermission权限点由sql/init.sql预置(user:list/user:update/user:delete)。 安全约束:
- 内置超级管理员(
id=1)不可删除、不可停用;- 不能删除 / 停用当前登录用户自身;
- 密码以 BCrypt 哈希存储,长度 ≥ 6 位;
username不可通过本组接口修改。
权限点:user:list。用户列表(不含密码字段,含用户的角色信息)。
响应 200
[
{
"id": 1,
"username": "admin",
"nickname": "管理员",
"enabled": 1,
"created_at": "2026-09-22 14:00:00",
"roles": [ { "user_id": 1, "role_id": 1, "code": "ADMIN", "name": "超级管理员" } ],
"roleCodes": [ "ADMIN" ],
"roleNames": [ "超级管理员" ]
}
]
权限点:user:update。更新用户;字段留空或 null 表示不修改该字段。
请求体(三个字段均可省略)
{
"nickname": "新昵称",
"password": "newPwd123",
"enabled": true
}
响应 200(失败码:NOT_FOUND 用户不存在 / BAD_REQUEST 密码 < 6 位 / FORBIDDEN 禁用 ADMIN 或自身)
{ "id": 2, "username": "alice", "nickname": "新昵称", "enabled": 1, "created_at": "..." }
权限点:user:delete。删除用户(级联清理 sys_user_role)。
响应 200(失败:FORBIDDEN 不能删除 ADMIN 或自身 / NOT_FOUND 用户不存在)
{ "deleted": 2 }
权限点:user:update。启停用户。
请求体
{ "enabled": false }
响应 200(失败:FORBIDDEN 不能停用 ADMIN 或自身 / NOT_FOUND 用户不存在)
{ "id": 2, "username": "alice", "nickname": "爱丽丝", "enabled": 0, "created_at": "..." }
独立菜单权限体系,与接口权限(sys_permission)完全解耦:菜单可见性只由“用户的角色 → 角色被授予的菜单”决定(
sys_role_menu),不依赖任何权限点编码。因此管理端接口仅校验
ADMIN角色(不使用@RequirePermission);/current实时查库返回,修改菜单授权后无需重新登录即可生效(这与角色/权限需重新登录的机制不同)。用户可见菜单树 = 其所有角色被授予菜单的并集,下发时自动向上补全父级、剔除空目录。
登录态(@RequireAuth)。当前用户可见菜单树。
响应 200(未登录:401)
[
{
"id": 1, "parent_id": null, "name": "工作台", "type": "menu",
"route": "/dashboard", "component": "dashboard/index", "icon": "HomeFilled",
"sort": 1, "visible": 1, "status": 1, "created_at": "...", "children": []
},
{
"id": 2, "parent_id": null, "name": "系统管理", "type": "dir",
"route": null, "component": null, "icon": "Setting",
"sort": 1, "visible": 1, "status": 1, "created_at": "...",
"children": [
{
"id": 3, "parent_id": 2, "name": "用户管理", "type": "menu",
"route": "/system/user", "component": "system/user/index", "icon": "User",
"sort": 1, "visible": 1, "status": 1, "created_at": "...", "children": []
}
]
}
]
角色:ADMIN。全量菜单树(管理端,含停用/隐藏项)。
响应 200:同上树形结构,返回全部节点。
角色:ADMIN。新建菜单(自动授权给 ADMIN 角色)。
请求体
{
"parentId": null,
"name": "报表中心",
"type": "menu",
"route": "/report",
"component": "report/index",
"icon": "DataAnalysis",
"sort": 3,
"visible": 1,
"status": 1
}
响应 200:新建后的菜单记录(NOT_FOUND 不存在 / PARAM 名称缺失)。
角色:ADMIN。更新菜单(缺失字段沿用原值)。
请求体:同 POST(可只传需改字段)。
响应 200:更新后的菜单记录(NOT_FOUND:菜单不存在)。
角色:ADMIN。删除菜单,级联删除其全部子菜单并清理 sys_role_menu 关联。
响应 200 { "deleted": 6 }
角色:ADMIN。查询某角色被授予的菜单 id 列表。
响应 200
[ 1, 3, 7 ]
角色:ADMIN。覆盖式设置某角色拥有的菜单。
请求体
{ "ids": [1, 3, 7] }
响应 200
{ "roleId": 3, "menuIds": [1, 3, 7] }
表结构与种子数据见
sql/init.sql(DDL + 元数据 51 条)与sql/indicator_values_seed.sql(时序值)。 一个指标对应一组 URL:基础/api/indicators/{id}拿元数据,加/values拿时序,加/latest拿最新观测点。 51 个指标的id由种子数据固定,可在sql/init.sql的INSERT OR IGNORE INTO indicator(...)中查到。
登录态。指标元数据列表。
查询参数(均可选):
category 一级分类(GDP / 投资 / 出口 / 消费 / 通胀 / 供给 / 景气度)subcategory 二级分类region 区域(中国 / 美国)frequency 频度(日 / 周 / 月 / 季 / 年)响应 200
[
{
"id": 1, "category": "GDP", "subcategory": "现价GDP增速",
"name": "中国:GDP:现价:当季同比", "region": "中国", "frequency": "季",
"unit": "%", "wind_code": "X4608416", "source": "Wind",
"data_start": "1993-03", "data_end": "2026-06",
"refreshed_at": "2026-07-15", "remark": "同比"
}
]
登录态。单个指标元数据。
响应 200(NOT_FOUND 指标不存在)
{
"id": 1, "category": "GDP", "subcategory": "现价GDP增速",
"name": "中国:GDP:现价:当季同比", "region": "中国", "frequency": "季",
"unit": "%", "wind_code": "X4608416", "source": "Wind",
"data_start": "1993-03", "data_end": "2026-06",
"refreshed_at": "2026-07-15", "remark": "同比"
}
登录态。单个指标的时序值。
查询参数(均可选):
start 起始日期(yyyy-MM-dd 或 yyyy-MM,按 obs_date >= start 过滤)end 截止日期(obs_date <= end)limit 返回行数限制(与 start/end 可组合使用)order 排序方向,asc(默认,时间正序)/ desc响应 200(NOT_FOUND 指标不存在)
{
"indicator": {
"id": 1, "category": "GDP", "subcategory": "现价GDP增速",
"name": "中国:GDP:现价:当季同比", "region": "中国", "frequency": "季",
"unit": "%", "wind_code": "X4608416", "source": "Wind",
"data_start": "1993-03", "data_end": "2026-06",
"refreshed_at": "2026-07-15", "remark": "同比"
},
"count": 2,
"values": [
{ "obs_date": "2025-12-31", "value": 3.85 },
{ "obs_date": "2026-03-31", "value": 4.94 }
]
}
登录态。单个指标的最新观测点。
响应 200(NOT_FOUND 指标不存在)
{
"indicator": {
"id": 1, "category": "GDP", "subcategory": "现价GDP增速",
"name": "中国:GDP:现价:当季同比", "region": "中国", "frequency": "季",
"unit": "%", "wind_code": "X4608416", "source": "Wind",
"data_start": "1993-03", "data_end": "2026-06",
"refreshed_at": "2026-07-15", "remark": "同比"
},
"latest": { "obs_date": "2026-06-30", "value": 5.89 }
}
以下写接口均需
ADMIN角色 + 权限点(indicator:create/indicator:update/indicator:delete/indicator:value:write),由sql/init.sql预置。 元数据表indicator.id为INTEGER PRIMARY KEY(SQLite rowid),缺省时由数据库自动分配;wind_code全局唯一。 时序值indicator_value上有UNIQUE(indicator_id, obs_date)约束。
权限点:indicator:create。新增指标元数据。
请求体(category / name / frequency 必填;id 可选,缺省自动分配)
{
"id": 100,
"category": "GDP",
"subcategory": "现价GDP增速",
"name": "示例指标",
"region": "中国",
"frequency": "月",
"unit": "%",
"windCode": "X9999999",
"source": "Wind",
"dataStart": "2020-01",
"dataEnd": "2026-08",
"refreshedAt": "2026-09-15",
"remark": "示例"
}
响应 200(失败:BAD_REQUEST 必填字段缺失 / INDICATOR_EXISTS id 或 wind_code 重复):新建后的完整元数据。
权限点:indicator:update。更新元数据,缺失字段沿用原值。
请求体:同 POST(可只传需改字段;id / category / name / frequency 缺省时保持原值)。
响应 200(NOT_FOUND 指标不存在 / INDICATOR_EXISTS wind_code 被其它指标占用):更新后的完整元数据。
权限点:indicator:delete。删除指标元数据,并级联清理其全部时序值(indicator_value.indicator_id 外键 ON DELETE CASCADE)。
请求体:无。
响应 200
{ "id": 12, "deleted": true, "valuesDeleted": 187 }
NOT_FOUND 指标不存在。
权限点:indicator:value:write。新增单条或批量时序值;与查询接口同路径,方法为 POST。
单条请求体
{ "obsDate": "2026-07-31", "value": 5.2 }
批量请求体(数组内每项 {obsDate, value};批量使用 INSERT OR IGNORE,已存在的 obs_date 被静默跳过,保证幂等)
{
"values": [
{ "obsDate": "2026-08-31", "value": 5.4 },
{ "obsDate": "2026-09-30", "value": 5.6 }
]
}
响应 200
{id, obs_date, value}(重复 obs_date 返回 VALUE_EXISTS);{indicatorId, requested, inserted, skipped}。权限点:indicator:value:write。按 obs_date upsert 单条值(不存在则创建)。
请求体
{ "value": 5.89 }
响应 200(NOT_FOUND 指标不存在):返回 {id, obs_date, value}。
通用文档管理:每个文档归属一个
indicator(任意category/subcategory,不再限制白名单), 用于把投研文档(央行货政报告、重要会议、产业政策、研究报告、合同模板……)统一上传、分类、检索、下载、摘要。数据源:
document+document_summary(表结构见sql/init.sql8 节)。 文件落盘目录:ir.upload.base-path(默认data/uploads/,部署可改为绝对路径)。 落盘子目录格式:{base-path}/{indicator.category}/{indicator.subcategory}/{period-title-uuid}.{ext}。 文件大小限制:单文件 20MB,请求体 25MB(spring.servlet.multipart.*)。 允许的扩展名白名单:pdf, doc, docx, xls, xlsx, ppt, pptx, txt, md, csv, json(在DocumentController.ALLOWED_EXTS追加即可扩展)。 权限点:document:create/document:update/document:delete/document:summary:write(仅 ADMIN 可写)。 前端菜单:数据管理 / 文档管理(id=31,route=/document/index,component=document/index)。
权限:登录。返回有文档的 (category, subcategory) 及文档数、最新期信息(左侧导航/分类树用)。
响应 200
[
{
"category": "政策面", "subcategory": "2.10 央行货币政策例会",
"indicator_id": 77, "indicator_name": "央行货币政策委员会例会",
"doc_count": 22, "latest_period": "2026Q2", "latest_title": "...", "latest_id": 1
}
]
权限:登录。按 category / subcategory 过滤;page/size 不传则返回全部。
Query:category / subcategory / page / size
响应 200
{
"count": 22,
"items": [
{
"id": 1, "category_id": 77, "period": "2026Q2", "period_year": 2026,
"title": "2026Q2-中国货币政策例会",
"file_path": "政策面/2.10 央行货币政策例会/2026Q2-2026Q2-中国货币政策例会-abcd1234.pdf",
"file_size": 222123, "publish_date": "2026-06-28", "page_count": 8,
"is_latest": 1, "sort_order": 1, "created_at": "...",
"category": "政策面", "subcategory": "2.10 央行货币政策例会", "indicator_name": "..."
}
]
}
权限:登录。一次性返回每个 subcategory 的 is_latest=1 文档 + 摘要(工作台/首页用)。
响应 200:数组,每项包含文档字段 + summary {overall_tone, policy_stance, risk_control, key_points_json, summary_updated_at}。
权限:登录。返回单个文档详情,summary 字段可能为 null。
权限:登录。流式返回文件二进制,触发浏览器下载(Content-Disposition: attachment; filename="<title>.<ext>")。
Content-Type 按扩展名自动匹配(pdf/doc/xls/ppt/...),未识别时返回 application/octet-stream。
权限:登录。内联返回文件二进制(Content-Disposition: inline),供浏览器/<iframe> 直接渲染:
pdf → 浏览器内置 PDF 阅读器;txt / md / csv / json → 文本展示;DocumentController.ALLOWED_EXTS 加上 png/jpg/jpeg/gif/webp 后即可预览;doc / xls / ppt 等 Office 文档浏览器无内置渲染,会回退到下载行为(建议前端降级为 /download)。
附带 X-Content-Type-Options: nosniff 防止 MIME 嗅探。权限点:document:create。上传文件 + 创建元数据。
请求(multipart/form-data):
| 字段 | 必填 | 说明 |
|---|---|---|
file |
是 | 文件(扩展名必须在白名单内) |
categoryId |
是 | 任意 indicator.id(不再限制白名单) |
period |
是 | 例:2026Q2 / 2025年 / 2026-07-30 |
title |
是 | 例:2026Q2-中国货币政策例会 |
periodYear |
否 | 整数 |
publishDate |
否 | YYYY-MM-DD |
pageCount |
否 | 整数 |
isLatest |
否 | 0/1,默认 1;会自动取消同分类其它文档的 latest 标记 |
sortOrder |
否 | 整数,默认 0 |
响应 200:DOC_EXISTS 表示 (category_id, period) 已存在;返回完整文档对象。
权限点:document:update。更新元数据;如同时传 file 则替换磁盘文件(旧文件删除)。
请求(multipart/form-data):字段同 POST;未传的字段保留原值;file 不传则不改文件。
权限点:document:delete。删除文档(级联删除 document_summary)与磁盘文件。
响应 200:{id, dbDeleted, fileDeleted}。
权限点:document:summary:write。整体替换式 upsert 摘要。
请求体(application/json)
{
"overallTone": "坚持稳中求进",
"policyStance": "稳健偏宽松",
"riskControl": "防范资金空转",
"keyPointsJson": "[{\"section\":\"汇率\",\"text\":\"防止超调\",\"change\":\"强调\"}]"
}
响应 200:返回更新后的文档详情。
| code | HTTP | 说明 |
|---|---|---|
TOKEN_INVALID |
200 | Token 无效或已过期 |
UNAUTHORIZED |
401 | 未登录(见 /api/auth/me、拦截器) |
FORBIDDEN |
403 | 无角色/权限 |
BAD_CREDENTIALS |
200 | 用户名或密码错误 |
USER_EXISTS |
200 | 用户名已被注册 |
USER_DISABLED |
200 | 账号已禁用 |
USER_NOT_FOUND |
200 | 用户不存在 |
ROLE_EXISTS / PERMISSION_EXISTS |
200 | 编码重复 |
NOT_FOUND |
200 | 资源不存在 |
BAD_REQUEST |
200 | 请求参数不合法 |
DB_ERROR |
500 | 数据源异常 |
INTERNAL_ERROR |
500 | 服务器内部错误 |