7.2 KiB
title, description, pageClass
| title | description | pageClass |
|---|---|---|
| 快速开始 | 接口约定、鉴权与联调步骤 | g3-api |
快速开始
后端提供的是一套元数据驱动的通用数据接口:前端不拼业务 SQL,只声明「查哪张视图 / 存哪张表 + 条件 + 字段」,由后端按 s_module / s_field 里的配置生成参数化 SQL 并执行。除登录外,所有接口共用同一套鉴权、机构数据源路由与统一响应格式。
基础约定
| 项 | 约定 |
|---|---|
| 基础路径 | /api(server.servlet.context-path),例如 http://localhost:8088/api/data/page |
| 方法 | 全部是 POST;唯一的 GET 是文件静态访问 /api/file/static/{fileName} |
| 请求体 | application/json,参数是一个对象或数组,不是表单 |
| 编码 | UTF-8 |
| HTTP 状态码 | 始终是 200 —— 成败一律看响应体里的 code,不要用 HTTP 状态码判断 |
最后一条最容易踩:鉴权失败、参数错误、系统异常都不会返回 4xx / 5xx,而是 200 + code != 0。所以不要依赖 axios 的错误拦截分支来处理业务失败。
统一响应格式
所有接口返回同一个外壳:
{
"code": 0,
"message": "操作成功",
"data": {}
}
| 字段 | 说明 |
|---|---|
code |
0 成功,非 0 见下表 |
message |
可直接展示给用户的文案;出错时是原因 |
data |
成功时的载荷;失败时一般为 null |
错误码
| code | 含义 | 触发场景 | 前端应对 |
|---|---|---|---|
0 |
成功 | —— | —— |
401 |
未登录 / 凭证失效 | 缺少或无效的 Authorization;账号密码错误 |
清 token,回登录页 |
40101 |
账号已在其他设备登录 | 同一账号在别处登录,本端会话被顶 | 清 token,提示后回登录页 |
1000 |
业务错误(默认) | 参数缺失或类型不对、标识符非法、只读 SQL 校验不通过、目标表没有可识别字段等 | 直接用 message 提示 |
2001 |
保存失败 | 写入时的数据库错误,data 带 table / action / index / cause |
提示 message;data.index 可定位到第几行 |
2002 |
保存前置条件不成立 | 请求声明的 guard 条件不满足,data 带 table / action / index |
直接用 message(那是写条件的人给的业务文案) |
2003 |
并发编辑冲突 | $original 原值或 b_row_version 不匹配,data 带 fields |
提示后重新拉取该行,标出 fields 里的字段 |
500 |
系统异常 | 未预期的异常 | 提示「系统异常,请稍后重试」 |
参数类错误都是 1000,message 形如 view_name 不能为空、page_no 必须是大于 0 的整数、参数类型不正确、非法数据库标识符: xxx —— 通常已经说清是哪个参数错了。
鉴权
登录
curl -X POST http://localhost:8088/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"orgid":"G3HD","userid":"admin","password":"******"}'
{
"code": 0,
"message": "操作成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiJ9...",
"orgid": "G3HD",
"user": { "id": "g3soft", "account": "g3soft", "name": "G3Soft" }
}
}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
orgid |
string | 是 | 机构码,决定连哪个机构的数据库 |
userid |
string | 是 | 账号;字符串业务键方案下 b_user.b_id 就是账号本身 |
password |
string | 与库里存的密码比对 |
机构码或账号为空 → 1000(机构码不能为空 / 用户ID不能为空);账号、密码、机构任一对不上 → 统一 401 + 机构码、账号或密码错误(刻意不区分是哪一个错)。
带上凭证
除 /api/auth/login 与 OPTIONS 预检外,所有接口都要带:
Authorization: Bearer <token>
机构码不用在业务接口里传。 token 里带着
orgId,服务端据此把请求路由到该机构自己的数据库,前端只管带 token。token 默认 24 小时过期(
erp.auth.jwt-expiration)。同一账号再次登录会让旧 token 失效并返回40101。
最小可跑示例
const api = axios.create({ baseURL: '/api' })
api.interceptors.request.use((config) => {
const token = localStorage.getItem('g3erp:token')
if (token) config.headers.Authorization = `Bearer ${token}`
return config
})
// HTTP 200 也可能是业务失败,所以要在这里统一判 code
api.interceptors.response.use((res) => {
const { code, message } = res.data
if (code === 401 || code === 40101) {
localStorage.removeItem('g3erp:token')
location.href = '/login'
}
return res.data
})
// 分页查询
const { data } = await api.post('/data/page', {
view_name: 'v_b_othercompany',
search_columns: ['b_id', 'b_name'],
search_condition: 'b_canuse = 1',
order_by: 'b_id ASC',
page_no: 1,
page_size: 20,
})
// data.rows / data.total / data.page_no / data.page_size
一个必须知道的序列化约定
所有长整型(Long)都以 JSON 字符串输出(后端 JacksonConfig 给 Long / long 注册了 ToStringSerializer):
{
"code": 0,
"message": "操作成功",
"data": "1873456789012345678"
}
原因是雪花 ID 是 64 位,超过 JS 的 Number.MAX_SAFE_INTEGER(2⁵³−1),按数字解析会静默丢精度。所以 data.nextid、行里的各种 id 一律当 string 处理,不要 Number() / parseInt(),也不要参与算术。
接口一览
- 数据查询 —— 数据查询:
/data/describe、/data/loaddata、/data/page、/data/loaddatabysql、/data/nextid、/data/nextcode - 数据写入 —— 数据写入:
/data/saveobjt、/data/delete - 鉴权 —— 本页:
/auth/login - 文件 —— 暂无专页:
/file/config、/file/upload、/file/upload-credential、/file/save-record、/file/delete、GET /file/static/{fileName} - 导出 —— 暂无专页:
/export/list、/export/count、/export/totals(返回文件流,不是ApiResponse)
/file/static/{fileName}同样受鉴权过滤(只有/auth/login被放行),所以不能用<img src="...">直接访问,需要按 blob 取回再用URL.createObjectURL。
联调步骤
- 起后端:
cd server && ./mvnw spring-boot:run(默认 8088);前端 dev server 的/api代理到它。 - 调
/api/auth/login拿 token,存进localStorage(键名沿用组件库示例里的g3erp:token)。 - 用
/api/data/describe看目标表或视图有哪些列,再调/api/data/page取数据。 - 拿到
code != 0先查上面的错误码表;1000的message基本能直接告诉你哪个参数不对。