开发规范

前端接入与联调指南

核对接口、权限、状态能力、查询、分页和前端交互。

浏览全部手册
本页目录
文档来源与 Markdown 原文

权威正文:ineed-core/docs/project-development/frontend-integration-guide.md。网站按工作区快照同步,原文中的历史日期和验证范围保留。

开始编码前核对同版本源码;跨仓文件引用可在源码定位目录查找。

下载 Markdown 原文 ↓

文档定位

本文档面向:

  • 前端开发者
  • 负责前后端联调的后端开发者
  • 编写业务需求说明的人

重点回答三类问题:

  • 前端在 ineed-core 里真正应该依赖哪些稳定契约
  • webmvcwebflux 两条线对前端来说哪些语义必须保持一致
  • 新业务模块在需求阶段,哪些前端信息必须先写清楚,避免后续返工

如果你要先理解当前框架模块边界,先读 module-capability-map.md。 如果你要新建业务模块,继续读 business-module-layout-guide.md。 如果你要写业务需求说明,继续读 module-requirements-template.md。 如果你要用代码生成器或自动化工具同时生成后端和前端,继续读 development-contract.mdcode-style-guide.md

前端只依赖这些稳定契约

前端不应直接围绕 entityrepository、数据栈实现做联调。

前端真正应该依赖的是:

  • AO 作为创建、编辑、导入等提交对象
  • Query 作为业务筛选条件对象
  • CommonParameters 作为分页、搜索、排序等通用查询参数
  • VO 作为列表、详情、树、字典等展示对象
  • ResponseResults<T> 作为统一响应外壳
  • QueryResults<T> 作为分页结果对象

这套契约主要位于:

  • ineed-core-base
  • ineed-core-webmvc
  • ineed-core-webflux

新业务模块面向前端的对象应位于后端 core 子模块的 contract/aocontract/querycontract/vocontract/dto 包下。需求、接口说明和前端联调文档统一称为 AO / Query / VO / DTO 契约对象,不再把这些对象写成 pojo

当前前端实现主要通过以下入口消费这些契约:

  • ineed-frontend/src/shared/api/request.js 统一注入 token,处理 ResponseResults、HTTP 错误和登录过期。
  • ineed-frontend/src/shared/api/serviceFactory.js 通过 createConfigCrudService(url, options) 组合标准 CRUD / query / data status / recycle API。
  • ineed-frontend/src/shared/store/storeFactory.js 通过 createConfigCrudStore(storeId, service, options) 组合列表、编辑、详情、回收站和状态动作。
  • ineed-frontend/src/shared/composables/support/dataStatusActionConfigs.js 定义状态按钮、权限后缀、显示条件和确认文案。
  • ineed-frontend/src/app/router/index.js 使用路由 meta.resourceKeymeta.resourceKeyBuilder 做页面级权限判断。

新模块前端代码应优先复用这些工厂和约定,只有领域特有接口才在模块自己的 service/*.js 里额外补方法。

登录 Token 与在线会话

当前安全框架把 JWT 当作前后端传输凭证,服务端 Session 才是登录状态的权威来源。

前端接入时遵守:

  • 登录接口返回的 token 只需要按统一 request 层注入到后续请求中,前端不要解析 token 内容来判断登录身份、租户或权限。
  • JWT 只承载最小会话标识,例如 sid;不要依赖 JWT 里的过期时间、用户字段或权限字段驱动页面状态。
  • token 是否仍有效由后端通过 Redis Session 校验兜底;前端收到统一未登录 / 会话失效错误后,按错误码进入重新登录或刷新当前登录态流程。
  • 在线会话管理接口使用 /security/online-session 语义,资源标识使用 security.online-session;不要继续生成或消费旧的用户维度在线管理路径与资源标识。
  • 在线会话列表面向 OnlineSessionVO,展示字段来自 VO;强制下线等动作以 sid 为目标会话标识,不要用用户名、用户 ID 或 token 全串作为操作主键。
  • Redis 在线会话索引语义是 ONLINE_SESSION,前端、文档、测试样例不要继续引用旧的 ONLINE 命名。

AO / Query / VO 的前端语义

AO

AO 是前端提交给后端的应用对象,主要用于:

  • 新增表单
  • 编辑表单
  • 批量导入
  • 自定义业务动作入参

基础约束来自 AbstractAO

  • 统一带 id
  • 保存时 id 必须为空
  • 更新时 id 不能为空

这意味着前端在新增和编辑时,不能把同一份未区分状态的表单对象直接复用成两套语义。

Query

Query 是业务筛选条件对象,只承载业务字段,不承担分页与排序。

例如:

  • 名称
  • 编码
  • 类型
  • 状态
  • 时间区间

分页、搜索关键字、排序这些通用参数不应塞进业务 Query 里,而是继续通过 CommonParameters 传递。

VO

VO 是前端看到的展示对象,主要用于:

  • 列表行
  • 详情页
  • 树节点
  • 字典项
  • 导出对象

基础约束来自 AbstractVO

  • 统一带 id

同一个业务对象在 webmvcwebflux 两条线中的 VO 字段语义应保持一致,不允许一边有字段、另一边缺字段。

通用查询参数怎么传

标准查询入口会把前端传入的 CommonParameters + Query 组装成 QueryParameters

前端真正需要关注的是 CommonParameters

  • dc 防缓存动态参数
  • searchKey 通用关键字搜索
  • current 当前页码
  • pageSize 每页条数
  • sortJson 排序 JSON 字符串

sortJson 对应的排序对象字段为:

  • property 排序属性。这里必须传后端实体属性名,例如 createdTimestamp,不要传 SQL 片段、列别名表达式或 id desc 这类拼接内容。
  • direction 排序方向,支持 ascASCascenddescDESCdescend

当前 JDBC / R2DBC / MyBatis-Flex 标准查询实现会按实体字段做排序白名单校验。非法或未知的 property 不应作为有效排序条件进入 SQL。

标准查询接口对前端更接近下面这种调用方式:

GET {controllerRoot}
  ?current=1
  &pageSize=20
  &searchKey=zhang
  &sortJson=[{"property":"createdTimestamp","direction":"descend"}]
  &name=张三
  &enabled=true

其中:

  • current / pageSize / searchKey / sortJson 来自 CommonParameters
  • name / enabled 这类业务字段来自具体 Query

除非某个自定义接口明确要求,否则前端不需要自己手工构造 QueryParameters JSON。

当前前端服务与 Store 落地方式

标准模块的前端服务通常长这样:

import request from '@/shared/api/request';
import { API_PREFIX } from '@/shared/config/constants';
import { createConfigCrudService } from '@/shared/api/serviceFactory';

const URL = 'business/customer';

export const customerDataStatusCapabilities = {
    enable: true,
    lock: false,
    default: false,
    primary: false,
    publish: false,
    reserve: false
};

export default {
    ...createConfigCrudService(URL, { dataStatusCapabilities: customerDataStatusCapabilities }),
    findProfile(id) {
        return request.get(`${API_PREFIX}/${URL}/${id}/profile`);
    }
};

约定如下:

  • URL 不带 /api 前缀,由 createConfigCrudService 内部拼接 API_PREFIX
  • 只有自定义接口需要直接引用 API_PREFIX
  • dataStatusCapabilities 必须来自需求或后端实体的 DataStatusFeature 开关,不能默认全开。
  • Store 优先使用 createConfigCrudStore(storeId, service, { tree, dataStatusCapabilities })
  • 如果模块是树结构,前端 service/store 要同时打开 tree: true 并确认后端提供 /tree 查询能力。

字段和页面代码应围绕 AO / Query / VO 分开设计:

前端文件类型 对应后端契约 说明
service/*.js Controller 路径与标准后缀 只封装 API,不承载页面状态
store/*.js ResponseResults / QueryResults 只处理加载、列表、编辑、详情、动作状态
routes.js resourceKey / 页面入口 路由 meta.resourceKey 必须能映射到后端权限点
pages/*.vue VO / Query / action 能力 组合表格、表单、状态动作和自定义页面行为
schema / columns 文件 AO / Query / VO 字段 维护表单字段、查询字段、列表列、详情字段、校验规则

如果一个模块没有 schema/columns 独立文件而是内联在页面中,新增字段时也必须按上表逐项核对,不要只改表单或只改列表。

统一返回外壳

无论是 webmvc 还是 webflux,对前端可见的统一响应模型都应保持同一语义:

  • traceId 请求追踪号
  • success 是否成功
  • errorCode 业务错误码
  • errorMessage 错误消息
  • alertMessage 友好提示
  • data 业务数据

成功响应示例:

{
  "traceId": "7a1c6f3a0f0d4e84",
  "success": true,
  "errorCode": null,
  "errorMessage": null,
  "alertMessage": "保存成功",
  "data": {
    "id": "1001",
    "name": "示例对象"
  }
}

分页响应示例:

{
  "traceId": "7a1c6f3a0f0d4e84",
  "success": true,
  "data": {
    "total": 52,
    "first": 1,
    "pageCount": 3,
    "pageSize": 20,
    "current": 1,
    "list": [
      {
        "id": "1001",
        "name": "示例对象"
      }
    ]
  }
}

前端联调时建议遵守:

  • 先按 HTTP 状态码区分是否成功返回
  • 再按 success 做业务成功判断
  • 任何异常反馈都保留 traceId,便于后端排查
  • alertMessage 作为提示文案使用,不要把它当成错误码
  • 需要分支处理时优先依赖 errorCode,不要只匹配中文报错文案

分页对象语义

标准分页对象 QueryResults<T> 至少包含:

  • total 总记录数
  • first 第一条序号
  • pageCount 总页数
  • pageSize 每页条数
  • current 当前页码
  • list 当前页数据

前端表格、分页器、导出预览应统一围绕这组字段消费,不要为不同数据栈分别写三套分页适配。

标准接口能力一览

控制器根路径由业务控制器自己的类级 @RequestMapping 决定。 下面列的是标准后缀语义,来源于 CoreConstant.Urls

能力 方法 标准路径后缀 典型入参 典型返回
创建 POST {root} AO ResponseResults<VO>
批量创建 POST {root}/batch Collection<AO> ResponseResults<Iterable<VO>>
更新 PUT {root} AO ResponseResults<VO>
详情 GET {root}/{id} id ResponseResults<VO>
批量详情 GET {root}/batch?idSet=... idSet ResponseResults<Iterable<VO>>
条件查询 GET {root} CommonParameters + Query ResponseResults<QueryResults<VO>>
逻辑删除 DELETE {root}/{id} id ResponseResults<Void>
批量逻辑删除 DELETE {root}?idSet=... idSet ResponseResults<Void>
恢复 PUT {root}/recovery/{id} id ResponseResults<Void>
批量恢复 PUT {root}/recovery Set<String> ResponseResults<Void>
启用/禁用 PUT {root}/enable/{id}{root}/disable/{id} id ResponseResults<Void>
锁定/解锁 PUT {root}/lock/{id}{root}/unlock/{id} id ResponseResults<Void>
发布/撤销发布 PUT {root}/publish/{id}{root}/withdraw/{id} id ResponseResults<Void>
默认/取消默认 PUT {root}/default/{id}{root}/non-default/{id} id ResponseResults<Void>
主要/取消主要 PUT {root}/primary/{id}{root}/non-primary/{id} id ResponseResults<Void>
账号能力 PUT {root}/account/passwd/reset/{id} id ResponseResults<Void>

如果某个实体没有开启对应数据状态能力,前端不要默认假定这些按钮和接口一定存在。

注意:当前前端通用 data status helper 中,发布的反向动作使用了 non-publish 命名;而 CoreConstant.Urls 和 WebMvc/WebFlux IPublishController 使用的是 withdraw。在代码统一前,启用 publish 能力的模块必须显式确认前端调用路径与后端控制器一致,不能盲目依赖默认 helper。

URL 命名与迁移调整

业务 URL 应优先表达稳定资源层级,不要把多个资源语义压成一个横线单词。遇到历史 URL 调整时,先做全量扫描和影响面确认,再一次性对齐后端、前端、权限清单和测试。

统一命名规则:

  • 前端页面路径使用业务层级,例如 /resource/number/serial/definition/resource/number/serial/pool/resource/number/serial/data
  • 后端管理 API 与页面层级保持同一资源语义,例如 /api/resource/number/serial/definition
  • 后端运行时 API 仍按运行时入口分组,例如 /api/runtime/resource/number/serial/{applicationKey}/{serialNumberKey}/preview
  • createConfigCrudService(url, options) 里的 url 不带 /api,但必须和后端 Controller 根路径去掉 API_PREFIX 后一致。
  • permissionUrl 中,menu/page 写前端访问路径,api 写后端接口路径;两者都要随 URL 调整同步更新。
  • resourceKey、模块目录、组件路径不因为 URL 层级调整而机械改名,除非需求明确要求一起重命名。

调整步骤:

  1. 先用全文搜索列出旧路径的所有出现位置,至少覆盖后端常量、Controller、权限清单、前端 routes/service/store/page、mock、E2E。
  2. 确定目标路径后,后端优先修改模块 Constant.Urls,避免 Controller 中散落字面量路径。
  3. 同步更新权限清单中的前端菜单 URL 和后端 API URL,确保授权后台看到的路径与真实入口一致。
  4. 同步更新前端 routes.js、模块 service/*.js、运行时自定义接口和 Playwright 用例。
  5. 如果运行时接口的路径参数语义变化,例如从 ruleKey 变为 applicationKey + serialNumberKey,前端页面和 service 方法签名必须一起调整,不能只替换 URL 字符串。
  6. 对兼容 redirect 明确做产品决策:需要兼容时只保留列出的旧入口;要求“一刀切”时删除旧路由和旧 API,不留下临时 redirect。
  7. 修改后再次搜索旧 HTTP 路径,确认没有新增残留;保留的模块目录名、import 路径或 resourceKey 需要能解释清楚。
  8. 在脏工作区中提交时,只暂存本次 URL 调整相关 diff。混有无关改动的文件必须用 selective staging 或 git apply --cached 精确暂存,再用 git diff --cached 复核。

调整示例:

旧页面:/resource/serial-number-definition/manage
新页面:/resource/number/serial/definition

旧 API:/api/resource/serial-number/definition
新 API:/api/resource/number/serial/definition

旧运行时 API:/api/runtime/resource/serial-number/{ruleKey}/preview
新运行时 API:/api/runtime/resource/number/serial/{applicationKey}/{serialNumberKey}/preview

webmvcwebflux 对前端必须保持一致的点

新增功能默认应同时评估 webmvcwebflux 两条线。

对前端来说,必须保持一致的不是“是不是 Mono”,而是下面这些外部语义:

  • 控制器根路径语义
  • URL 后缀语义
  • resourceKey 与按钮权限点
  • AO / Query / VO 字段集合
  • ResponseResults 外壳
  • QueryResults 分页字段
  • HTTP 状态码语义
  • errorCode 与错误消息语义

前端不应因为后端采用 webflux 就另写一套接口字段解析逻辑。 对前端而言,Mono<ResponseResults<T>>ResponseResults<T> 的区别属于服务端实现细节,不应演变成两套 JSON 契约。

按钮权限点与 resourceKey

IWebMvcApiIWebFluxApi 都要求业务控制器提供 getResourceKey()getResourceName()

getResourceKey() 是稳定权限资源标识,getResourceName() 是业务展示名。OpenAPI 输出公共接口摘要时会用 getResourceName() 替换 资源 占位,例如 创建资源 输出为 创建系统身份。 业务控制器应优先从模块常量读取这两个值:XxxConstant.Resource.KEY_* / XxxConstant.Resource.NAME_*

最终权限点通过:

resourceKey + "." + action

拼出来。

permissionKey 统一使用点号分隔,禁止使用 :。推荐格式为 {moduleKey}.{resource}.{action},例如 platform.area.create

权限清单中需要同时区分目录、前端导航、后端接口和页面按钮:

  • catalog 表达目录或分组,不对应具体前端组件或后端接口,也不配置 permissionUrl / component
  • menu 表达独立前端菜单入口,permissionUrl 填前端访问路径,component 填真实前端组件路径,icon 只给可见菜单节点使用。
  • page 表达隐藏/从属页面,不独立出现在菜单中,例如详情、编辑、配置、主从资源子列表页;这类页面通常依赖主资源 ID,后端会出现 ISearchOfMasterIdController / search-of-master-id 能力。
  • apipermissionUrl 填后端接口路径,用于表达查询、详情、字典、回收站查询、search-of-master-id 等接口能力。
  • button 只表达页面上的可见操作按钮,不填 permissionUrl/component/icon
  • 不要把多个独立菜单入口错误包在一个 menu 下再生成为 page。需要中间分组时使用 catalog,例如 安全中心 catalog -> 系统身份管理 catalog -> 系统身份 menu / 系统身份分组 menu
  • orderWeight 按权限树 DESC 规则设计,权重越大越靠前;推荐顺序是辅助查询 API、列表查询、CRUD、状态操作、回收站操作。
  • permissionDescription 面向后台授权人员阅读,必须写业务语义,不要把 idSetID 集合querycommonParameters 等后端参数名写进说明。

常见 action 取值来自 CoreConstant.ResourceKey,例如:

  • create
  • batch-create
  • update
  • logic-delete
  • batch-logic-delete
  • find-by-id
  • batch-find-by-id
  • recovery
  • enable
  • disable
  • lock
  • unlock
  • publish
  • default
  • primary
  • account-passwd-reset

因此需求说明里必须提前写清:

  • 控制器根路径
  • resourceKey
  • 页面按钮和权限点映射
  • 路由 meta.resourceKeymeta.resourceKeyBuilder

否则前端菜单、按钮显隐和后端授权很容易对不上。

当前前端权限判断还会做少量历史动作别名兼容:

  • save 可以映射到 create
  • details 可以映射到 detailsfind-by-id
  • recycle 可以映射到 recovery
  • physics-delete 可以映射到 physics-deletelogic-delete

这些别名只用于兼容前端权限判断,不应作为新后端权限命名的依据。新接口仍应优先使用 CoreConstant.ResourceKey 中的标准 action。

导入导出与 Excel 约定

AO / VO 不只是表单和展示对象,也要预留后续导入导出能力。

当前约定是:

  • 需要导入的对象优先落在 AO
  • 需要导出的对象优先落在 VO
  • 只要业务已经明确存在导入导出场景,就应在 AO / VO 上直接考虑 @ExcelProperty
  • 即使当前阶段暂未接入 Excel,也要先把字段中文名、列含义、顺序、是否必填写进需求,避免后续返工

需求里至少要先写清:

  • 哪些字段参与导入
  • 哪些字段参与导出
  • 列头中文名
  • 是否需要模板下载
  • 是否允许部分字段只导出不导入

写需求时前端信息至少补齐这些

参考 module-requirements-template.md,前端相关内容至少要补齐:

  • 控制器根路径
  • resourceKey
  • 页面路由或页面入口
  • 列表字段
  • 查询字段
  • 详情字段
  • 创建字段
  • 编辑字段
  • 默认排序
  • 按钮权限点
  • 是否需要回收站
  • 是否需要状态切换
  • 是否需要账号能力
  • 是否需要导入导出
  • 导入导出列头与字段映射
  • 是否要求 webmvcwebflux 两条线都开放同等能力
  • 前端模块路径,例如 ineed-frontend/src/modules/business/customer
  • service/store/page/route/schema 是否都需要新增或修改
  • 是否复用 createConfigCrudService / createConfigCrudStore
  • dataStatusCapabilities 的明确取值
  • 路由名称、路由 path、菜单标题和页面级 resourceKey
  • 表格列、查询项、创建表单、编辑表单、详情面板是否字段一致
  • 自定义接口的 URL、方法、入参、返回 data 结构和错误码
  • Playwright E2E 是否需要新增 fixture、登录凭据依赖和跳过条件

前端代码生成的最小输入

如果用代码生成器或自动化工具处理前端联调、页面字段整理任务,输入至少要提供:

后端 Controller 根路径:
后端 resourceKey:
前端模块目录:
路由 path/name/meta.resourceKey:
列表列:
查询字段:
创建 AO 字段:
编辑 AO 字段:
详情 VO 字段:
默认排序:
dataStatusCapabilities:
自定义接口:
需要新增或更新的 service/store/page/schema/routes:
需要新增或更新的 Playwright 用例:

实现前必须先核对后端 AO / Query / VO / Controller 与前端字段表是否一致;字段不一致时先报告缺口,不要自行猜字段。

联调检查清单

  • 前端是否只依赖 AO / Query / VO / ResponseResults / QueryResults
  • 列表分页是否统一消费 current / pageSize / total / list
  • 查询接口是否通过 CommonParameters + Query 传参,而不是自造分页对象
  • 是否保留并展示 traceId
  • 是否按 errorCode 做业务分支,而不是硬编码中文文案
  • 页面按钮权限点是否与 resourceKey.action 一致
  • 页面路由、后端 API、权限清单、service URL 和 E2E 是否使用同一套资源路径
  • URL 迁移后是否已搜索旧路径,且兼容 redirect 是否符合本次决策
  • 如果有导入导出,AO / VO 字段和列头是否已经在需求里写清
  • 如果本次功能是公共能力,webmvcwebflux 是否都已对齐

最后更新:2026-06-01

仍有疑问?按反馈清单整理复现信息 →