本文引用的文件
本文面向前端和后端维护者,系统性梳理 plat 模块下 /auth、/user、/sys、/case、/tpl、/tower 等控制器的 API 契约。重点包括:
/auth/login 获取 token,后续请求如何携带 x-token,Sa-Token 与会话活跃检测如何配合完成“账号占用确认”“强制登录”“顶下线”。plat 模块采用典型的 Spring MVC 分层:控制器负责路由和统一响应包装,服务层封装认证、用户管理、案件、系统和塔台业务,实体类描述数据库模型,DTO/VO 描述接口入参出参。
graph TB
Client["前端页面<br/>浏览器 / Electron"] --> Gateway["网关 / 反向代理"]
Gateway --> AuthCtl["/auth 认证控制器"]
Gateway --> UserCtl["/user 用户管理控制器"]
Gateway --> SysCtl["/sys 系统控制器"]
Gateway --> CaseCtl["/case 案件控制器"]
Gateway --> TplCtl["/tpl 表模板控制器"]
Gateway --> TowerCtl["/tower 塔台控制器"]
AuthCtl --> SysSvc["SysUserService<br/>认证 + 用户管理"]
UserCtl --> SysSvc
CaseCtl --> CaseSvc["CaseInfoService"]
TplCtl --> TableSvc["TableInfoService"]
TowerCtl --> TowerSvc["TowerService"]
SysCtl --> SystemSvc["SystemService"]
SysCtl --> HealthSvc["SystemHealthService"]
SysSvc --> Stp["Sa-Token<br/>会话与 Token"]
SysSvc --> DsReg["CaseDataSourceRegistry<br/>案件数据源注册表"]
SysSvc --> Cache["CaseDataCache<br/>案件数据缓存"]
图示来源
章节来源
/auth:提供登录、登出、当前用户信息、修改密码、校验密码。其中 /auth/login 在 Sa-Token 拦截器白名单中,其余接口需要登录。/user:用户分页列表、创建、更新、重置密码、删除、强制下线。所有接口要求当前用户是管理员。/sys:健康检查、系统服务探测、授权信息、机器码、离线授权激活、缓存清理、升级包上传、文件下载、本地文件打开、离线地图瓦片与样式等。/case:查询自己的案件列表、新建或更新案件、删除、更新案件密码、开启案件、退出案件、查询当前已打开案件。/tpl:模板分页查询、名称重复性检查、分类枚举、详情、创建、更新、删除。/tower:基站查询、上传基站 xls/xlsx 转换、下载转换模板。Result:所有业务接口返回 {code, message, data};成功默认 code 为 200,失败默认 code 为 400。AccountInUseException:账号正在其他设备使用时返回 HTTP 200 + body.code=40901,前端据此弹出是否继续登录的确认框。章节来源
认证与系统基础接口的关键交互如下:
sequenceDiagram
participant FE as "前端"
participant GW as "网关 / 反向代理"
participant AC as "认证控制器"
participant SVC as "SysUserService"
participant ST as "Sa-Token"
participant ACT as "登录活跃服务"
participant DS as "案件数据源注册表"
participant CACHE as "案件数据缓存"
FE->>GW: POST /auth/login {username,password,force}
GW->>AC: 转发登录请求
AC->>SVC: login(LoginDTO)
SVC->>ACT: isInUse(userId)
alt 账号正在使用且未 force
SVC-->>AC: 抛出 AccountInUseException
AC-->>FE: HTTP 200 {code:40901,message}
FE->>FE: 弹出确认框
FE->>GW: POST /auth/login {...,force:true}
GW->>AC: 转发强制登录
AC->>SVC: login(force=true)
SVC->>ST: kickout(userId)
SVC->>DS: 释放旧会话打开的案件
SVC->>CACHE: 清理旧会话案件缓存
SVC->>ST: login(userId)
SVC-->>AC: LoginVO{token,...}
AC-->>FE: {code:200,data:LoginVO}
else 正常登录
SVC->>ST: login(userId)
SVC-->>AC: LoginVO{token,...}
AC-->>FE: {code:200,data:LoginVO}
end
Note over FE,GW: 后续请求通过 x-token 携带令牌
图示来源
/auth| HTTP 方法 | URL | 鉴权 | 请求体 | 成功响应 | 说明 |
|---|---|---|---|---|---|
| POST | /auth/login |
无需登录 | {username,password,force?} |
{code:200,data:{token,userId,username,displayName,isAdmin}} |
登录;账号被占用且未 force 时返回 HTTP 200 + code=40901 |
| POST | /auth/logout |
可选(401 也允许) | 无 | {code:200} |
登出并释放该 token 打开的案件 |
| GET | /auth/info |
需登录 | 无 | {code:200,data:{id,username,displayName,isAdmin,status,createTime,lastLoginTime}} |
刷新页面后恢复用户态 |
| POST | /auth/changePwd |
需登录 | {oldPwd,newPwd} |
{code:200} |
自助修改密码 |
| POST | /auth/verifyPwd |
需登录 | {password?} |
{code:200,data:boolean} |
锁屏解锁;密码错返回 false 而非 401 |
登录请求字段
username:登录名,必填。password:明文密码,服务端用 BCrypt 比对,不落库。force:可选布尔值;当账号正在其他设备使用时首次登录返回 40901,用户确认后带 force=true 重新提交以接管旧会话。登录成功返回字段
token:Sa-Token 登录凭据,前端写入缓存后由请求拦截器注入 x-token 请求头。userId:用户 ID。username:登录名。displayName:显示名。isAdmin:1 为管理员,0 为普通用户。错误行为
章节来源
curl -X POST http://localhost:端口/auth/login -H "Content-Type: application/json" -d '{"username":"admin","password":"admin123"}'curl -X POST http://localhost:端口/auth/login -H "Content-Type: application/json" -d '{"username":"admin","password":"admin123","force":true}'/auth/login,设置 isTransformResponse:false,因为 40901 是正常分支。data.token,写入 localStorage,并在后续请求中通过 x-token 请求头携带。code===40901,弹出“是否确定登录”确认框;确认后再次调用同一接口并传入 force:true。章节来源
/user| HTTP 方法 | URL | 鉴权 | 请求体 | 成功响应 | 说明 |
|---|---|---|---|---|---|
| GET | /user/list |
管理员 | keyword?, page?, size? |
{code:200,data:Page<UserVO>} |
按登录名或显示名模糊匹配分页 |
| POST | /user/create |
管理员 | {username,password,displayName?,isAdmin?,status?} |
{code:200} |
新建用户 |
| POST | /user/update |
管理员 | {id,displayName?,isAdmin?,status?} |
{code:200} |
修改显示名、管理员标志、启用状态 |
| POST | /user/resetPwd |
管理员 | {id,newPassword} |
{code:200} |
重置密码并强制该用户下线 |
| POST | /user/delete |
管理员 | {id} |
{code:200} |
删除用户 |
| POST | /user/kickout |
管理员 | {id} |
{code:200} |
强制指定用户下线 |
分页字段
keyword:可选,模糊匹配登录名或显示名。page:可选,默认 1。size:可选,默认 20。data 是 MyBatis-Plus Page 对象,包含 current、size、total、records。用户返回字段
id:用户 ID。username:登录名。displayName:显示名。isAdmin:1 为管理员,0 为普通用户。status:1 为启用,0 为停用。createTime:创建时间。lastLoginTime:最后登录时间。错误行为
章节来源
/sys| HTTP 方法 | URL | 鉴权 | 请求体 | 成功响应 | 说明 |
|---|---|---|---|---|---|
| GET | /sys/health |
通常无需登录 | 无 | {code:200} |
健康检查 |
| GET | /sys/serviceHealth |
通常无需登录 | 无 | {code:200,data:[ServiceHealthDTO]} |
后端、PostgreSQL、Redis、Elasticsearch 可用性与耗时 |
| GET | /sys/info |
通常无需登录 | 无 | {code:200,data:SystemInfo} |
系统授权信息 |
| GET | /sys/code |
通常无需登录 | 无 | {code:200,data:string} |
服务器机器码 |
| POST | /sys/noNet |
通常无需登录 | multipart/form-data file=.xlts |
{code:200} |
离线授权激活 |
| GET | /sys/cleanCache |
通常无需登录 | 无 | {code:200} |
清理系统缓存 |
| POST | /sys/uploadUpgrade |
通常无需登录 | multipart/form-data file=zip |
{code:200} |
上传升级包并执行升级 |
| GET | /sys/downloadFile |
通常无需登录 | query fid=file_info.id |
文件流 | 按文件 ID 下载附件,不返回 Result |
| GET | /sys/map/pmtiles |
通常无需登录 | header Range? |
瓦片字节流 | 离线地图 PMTiles,支持 Range |
| GET | /sys/map/style |
通常无需登录 | 无 | 样式 JSON 或 404 | 离线地图自定义样式 |
系统信息字段
machinecode:机器码。clientNo:客户编号。unit:单位。phone:手机号。authdatetime:授权时间。overdatetime:过期时间。activeDateTime:激活时间。remainingDate:剩余天数,非数据库字段。错误行为
serviceHealth 会返回各服务的探测结果;整体仍可能走 200,但前端应读取 data 中的状态字段判断可用性。章节来源
/case| HTTP 方法 | URL | 鉴权 | 请求体 | 成功响应 | 说明 |
|---|---|---|---|---|---|
| GET | /case/list |
需登录 | 无 | {code:200,data:[CaseInfo]} |
仅返回当前登录用户自己的案件 |
| POST | /case/create |
需登录 | CaseInfo JSON |
{code:200} |
带 id 为更新,不带 id 为新建 |
| GET | /case/delete |
需登录 | query id |
{code:200} |
删除案件 |
| POST | /case/updatePwd |
需登录 | {id,newPwd} |
{code:200} |
更新案件密码 |
| POST | /case/open |
需登录 | {id,pwd?} |
{code:200,data:CaseInfo} |
开启案件,返回工作空间路径 |
| GET | /case/exit |
需登录 | 无 | {code:200} |
退出案件 |
| GET | /case/current |
需登录 | 无 | `{code:200,data:CaseInfo | null}` |
案件实体字段
id:案件 ID。name:案件名称。pwd:案件密码,写保护,不返回给前端。db:数据库名称,忽略序列化。dbPath:数据库路径,忽略序列化。type:案件类型。remark:备注。createTime:创建时间。init:是否初始化。ownerId:归属用户 ID。workspacePath:工作空间目录,非数据库字段,由服务端补回。错误行为
章节来源
/tpl| HTTP 方法 | URL | 鉴权 | 请求体 | 成功响应 | 说明 |
|---|---|---|---|---|---|
| GET | /tpl/page |
需登录 | table_name_cn?, has_inner?, classify?, page, limit |
{code:200,data:Page<TableInfo>} |
模板分页查询 |
| GET | /tpl/checkName |
需登录 | old_table_name_cn?, name |
`{code:200,data:"Y" | "N"}` |
| GET | /tpl/cag |
需登录 | 无 | {code:200,data:[string]} |
分类枚举 |
| GET | /tpl/detail |
需登录 | id |
{code:200,data:TableInfo} |
模板详情 |
| POST | /tpl/create |
需登录 | TableInfo JSON |
{code:200} |
创建模板 |
| POST | /tpl/update |
需登录 | TableInfo JSON |
{code:200} |
更新模板 |
| GET | /tpl/delete |
需登录 | id |
{code:200} |
删除模板 |
模板分页字段
table_name_cn:可选,中文表名模糊匹配。has_inner:可选,1 表示有内嵌,0 表示无内嵌。classify:可选,按类别过滤。page、limit:分页页码与每页条数。模板实体字段
id:主模版 ID。mainId:主模版 ID。tableNameCn:表名中文。tableNameEn:表名英文。headers:表头。classify:类别。hasInner:是否有内嵌。hasTable:是否有表。createTime:创建时间。funcRegx:模板函数正则。lineNo:表头行号。tableFields:表字段,非数据库字段。错误行为
/tpl 没有独立权限体系,但受全局登录拦截影响。章节来源
/tower| HTTP 方法 | URL | 鉴权 | 请求体 | 成功响应 | 说明 |
|---|---|---|---|---|---|
| GET | /tower/qry |
需登录 | mnc,lac,ci |
{code:200,data:[string]} |
基站查询 |
| POST | /tower/covFile |
需登录 | multipart/form-data file=xls/xlsx |
文件流 | 上传基站 xls 并转换,返回 xlsx 文件流 |
| GET | /tower/template |
需登录 | 无 | 文件流 | 下载基站转换模板 |
错误行为
章节来源
classDiagram
class AuthController {
+login(dto)
+logout()
+info()
+changePwd(dto)
+verifyPwd(dto)
}
class UserController {
+list(keyword,page,size)
+create(dto)
+update(dto)
+resetPwd(dto)
+delete(dto)
+kickout(dto)
}
class SystemController {
+health()
+serviceHealth()
+info()
+machineCode()
+noNet(file)
+cleanCache()
+uploadUpgrade(file)
+downloadFile(fid)
+mapPmtiles(range)
+mapStyle()
}
class CaseInfoController {
+list()
+create(caseInfo)
+delete(id)
+updatePwd(dto)
+open(dto)
+exit()
+current()
}
class TableInfoController {
+page(query)
+checkName(old,name)
+cag()
+detail(id)
+create(tableInfo)
+update(tableInfo)
+delete(id)
}
class TowerController {
+qry(mnc,lac,ci)
+covFile(file)
+template()
}
class SysUserService {
+login(dto)
+logout()
+info()
+changePwd(dto)
+verifyPwd(password)
+list(keyword,page,size)
+create(dto)
+update(dto)
+resetPwd(dto)
+delete(id)
+kickout(id)
}
AuthController --> SysUserService : "依赖"
UserController --> SysUserService : "依赖"
CaseInfoController --> CaseInfoService : "依赖"
TableInfoController --> TableInfoService : "依赖"
TowerController --> TowerService : "依赖"
SystemController --> SystemService : "依赖"
SystemController --> SystemHealthService : "依赖"
图示来源
章节来源
Page,默认 page=1、size=20;返回对象包含 current、size、total、records。TableInfoQuery 承载 page 和 limit,同样返回 MyBatis-Plus Page。StpUtil.kickout 并释放对应用户的案件数据源及缓存。/sys/uploadUpgrade 会执行版本校验、解压、覆盖数据库、执行升级 SQL,属于长耗时操作,前端应提供进度或超时提示。章节来源
x-token;检查前端是否在登录成功后写入 token;检查网关是否正确透传请求头。force=true 重新提交;服务端踢掉旧会话并让新会话登录。章节来源
/user/** 的用户不是管理员。isAdmin 是否为 1;检查前端是否误把普通用户引导到用户管理入口。章节来源
/sys/health;再调 /sys/serviceHealth 查看各子服务状态;检查部署环境配置。fid 是否正确;检查系统配置的离线地图目录是否存在样式文件。章节来源
StpUtil.kickout,释放该用户打开的案件数据源和缓存。章节来源
plat 模块的认证与系统基础接口以 Sa-Token 为核心,结合登录活跃检测实现“账号占用确认”和“强制登录”,并通过 x-token 请求头维持会话。用户管理接口仅限管理员,案件接口按 owner_id 隔离,表模板和塔台接口分别承担数据建模与基站处理能力。前端应在登录后持久化 token,在 401、403、40901 等场景下正确处理缓存清理和用户引导。运维侧可通过 /sys/health 和 /sys/serviceHealth 快速定位后端及依赖服务状态。