E:\workspace\zsjz-ai(后端 ai-server,前端 ai-frontend)@PutMapping / @DeleteMapping / @PatchMapping / @RequestMapping(method=PUT|DELETE|PATCH)。@RequestBody → 必须 POST。@RequestBody 时:形参 > 3 → POST;≤ 3 → GET。符合以下任一条件的接口,一律不改造,保持原样:
@GetMapping 的接口(含绑定 Query / DTO 对象形参的 GET);@RequestBody 的接口。本次实际改造范围 = 既不是 @GetMapping、又没有 @RequestBody 的接口。
只改「调用哪个请求方法」这一处,禁止改动任何已封装好的请求工具。 以下文件一个字节都不动:
| 文件 | 说明 |
|---|---|
src/core/utils/http/axios/Axios.ts |
底层 defHttp,其中 put() / delete() 方法保留(豁免项仍在用 put) |
src/core/utils/http/axios/index.ts |
beforeRequestHook / transformRequestHook 拦截逻辑 |
src/ai/api/http.ts |
aiHttp 封装,putRaw / deleteRaw / putJson / delete / withQuery 全部保留原样 |
前端改动只落在 api 层调用点(§3):defHttp.delete(...) → defHttp.get(...)、aiHttp.deleteRaw(...) → aiHttp.getRaw(...) 这类调用替换,不涉及工具本身。
| 类别 | 数量 | 处理 |
|---|---|---|
PUT / DELETE 且无 @RequestBody |
15 | 后端改 @GetMapping + 前端调用改 GET(清单见 §2) |
PUT / DELETE 且带 @RequestBody |
1(AgentModelController#updateModel) |
豁免,保持 @PutMapping 原样(§4.1) |
原本就是 @GetMapping |
47 | 豁免,不动 |
原本就是 @PostMapping(含带/不带 @RequestBody) |
82 | 豁免,不动 |
附带说明(不改造):5 个不带
@RequestBody的 POST(DmController.preFileUpload、AuthController.logout、SystemController.noNet、SystemController.uploadUpgrade、TowerController.covFile)按规则 3 本是 GET 候选,但它们已经是 POST,不违反任何规则,保持不动。
改造不动 URL 与路径变量,只换 HTTP 方法。路由、拦截器、Sa-Token 鉴权配置全部不变。
唯一例外(2 处,已执行):以下两个删除接口改 GET 后与既有 GET 详情接口同路径,会触发 Spring「Ambiguous mapping」启动异常,故加 /delete 后缀(与项目 /case/delete、/tpl/delete 风格一致),前端同步:
| 接口 | 原路径(DELETE) | 新路径(GET) | 冲突对象 |
|---|---|---|---|
AgentChatController#deleteSession |
/chat/sessions/{sessionId} |
/chat/sessions/{sessionId}/delete |
既有 GET /chat/sessions/{sessionId}(getSession) |
InsightController#deleteSession |
/insight/sessions/{id} |
/insight/sessions/{id}/delete |
既有 GET /insight/sessions/{id}(getSession) |
其余 13 处路径零变化。
| # | 文件(相对 ai-server/src/main/java/com/zsjz/ai/) |
行 | 现状 | 接口 | 形参 | 目标 | 前端传参 |
|---|---|---|---|---|---|---|---|
| 1 | module/agent/controller/AgentChatController.java |
62 | PUT | /chat/sessions/{sessionId}/title updateSessionTitle |
2(path+param) | GET | query: title |
| 2 | 同上 | 70 | DELETE | /chat/sessions/{sessionId}/chat/sessions/{sessionId}/delete deleteSession |
1 | GET | — |
| 3 | 同上 | 78 | PUT | /chat/sessions/{sessionId}/pin togglePinSession |
1 | GET | — |
| 4 | 同上 | 102 | DELETE | /chat/messages/{messageId} deleteMessage |
1 | GET | — |
| 5 | 同上 | 110 | PUT | /chat/messages/{messageId}/star toggleStarMessage |
1 | GET | — |
| 6 | module/agent/controller/AgentModelController.java |
65 | DELETE | /models/{id} deleteModel |
1 | GET | — |
| 7 | 同上 | 74 | PUT | /models/{id}/default setDefaultModel |
1 | GET | — |
| 8 | module/agent/insight/controller/InsightController.java |
114 | DELETE | /insight/sessions/{id}/insight/sessions/{id}/delete deleteSession |
2(path+param) | GET | query: caseId |
| 9 | module/person/controller/PersonBasicInfoController.java |
35 | DELETE | /pbi/delete delete |
1(String personName) |
GET | query: personName |
| 10 | module/person/controller/PersonGroupController.java |
73 | DELETE | /pg/remPerson remPerson |
1(Long relId) |
GET | query: relId |
| 11 | module/plat/controller/CaseInfoController.java |
63 | DELETE | /case/delete delete |
1(Long id) |
GET | query: id |
| 12 | module/plat/controller/TableInfoController.java |
87 | DELETE | /tpl/delete delete |
1(Integer id) |
GET | query: id |
| 13 | module/trans/controller/CashKeyController.java |
55 | DELETE | /trans/cashKey/delete delete |
1(Long id) |
GET | query: id |
| 14 | module/trans/controller/FinancialKeyController.java |
49 | DELETE | /trans/financialKey/delete delete |
1(Long id) |
GET | query: id |
| 15 | module/trans/controller/FixedDepositKeyController.java |
51 | DELETE | /fixedDepositKey/delete delete |
1(Long id) |
GET | query: id |
单参数(#2/#4/#6/#11/#12/#13/#14/#15):
// before
@DeleteMapping("/sessions/{sessionId}")
public void deleteSession(@PathVariable Long sessionId) { ... }
// after
@GetMapping("/sessions/{sessionId}")
public void deleteSession(@PathVariable Long sessionId) { ... }
带简单类型参数(#1/#8/#9/#10)——顺手补 @RequestParam,行为不变:
// before
@DeleteMapping("/delete")
public Result<Void> delete(Long id) { ... }
// after
@GetMapping("/delete")
public Result<Void> delete(@RequestParam Long id) { ... }
改为 GET 后删除无用 import 行 import org.springframework.web.bind.annotation.DeleteMapping;:
InsightController、CaseInfoController、TableInfoController、CashKeyController、FixedDepositKeyController。
AgentChatController、AgentModelController、PersonBasicInfoController、PersonGroupController、FinancialKeyController 用的是 web.bind.annotation.* 通配,不动。
只替换请求方法调用,不改任何封装工具(§1.3)。所有调用都走 api 层函数,视图组件只 import 函数名,改完 api 层后 .vue / store 层零改动(调用点见 §3.4)。
src/ai/api/chatApi.ts(5 处)// #1 before
return aiHttp.putRaw<void>(`/chat/sessions/${sessionId}/title`, undefined, { title });
// after
return aiHttp.getRaw<void>(`/chat/sessions/${sessionId}/title`, { title });
// #2 before
return aiHttp.deleteRaw<void>(`/chat/sessions/${sessionId}`);
// after(路径加 /delete,原因见 §1.5)
return aiHttp.getRaw<void>(`/chat/sessions/${sessionId}/delete`);
// #3 before
return aiHttp.putRaw<void>(`/chat/sessions/${sessionId}/pin`);
// after
return aiHttp.getRaw<void>(`/chat/sessions/${sessionId}/pin`);
// #4 before
return aiHttp.deleteRaw<void>(`/chat/messages/${messageId}`);
// after
return aiHttp.getRaw<void>(`/chat/messages/${messageId}`);
// #5 before
return aiHttp.putRaw<void>(`/chat/messages/${messageId}/star`);
// after
return aiHttp.getRaw<void>(`/chat/messages/${messageId}/star`);
src/ai/api/modelApi.ts(2 处)// #6 before
return aiHttp.delete<void>(`/models/${id}`);
// after
return aiHttp.get<void>(`/models/${id}`);
// #7 before
return aiHttp.putJson<void>(`/models/${id}/default`);
// after
return aiHttp.get<void>(`/models/${id}/default`);
modelApi.ts:27的updateModel(aiHttp.putJson)保持不动,对应后端 §4.1 豁免项。
// #8 src/graph/insight/api.ts:62
// before
return aiHttp.deleteRaw<void>(`${BASE}/sessions/${id}`, { caseId });
// after(路径加 /delete,原因见 §1.5)
return aiHttp.getRaw<void>(`${BASE}/sessions/${id}/delete`, { caseId });
// #9 src/person/api/personApi.ts:99
// before defHttp.delete<void>({ url: adminPath + '/pbi/delete', params: { personName } }, {...})
// after defHttp.get<void>({ url: adminPath + '/pbi/delete', params: { personName } }, {...})
// #10 src/person/api/personApi.ts:196
// before defHttp.delete<void>({ url: adminPath + '/pg/remPerson', params: { relId } }, {...})
// after defHttp.get<void>({ url: adminPath + '/pg/remPerson', params: { relId } }, {...})
// #11 src/plat/api/tpl/tplApi.ts:75
// before defHttp.delete<void>({ url: adminPath + '/tpl/delete', params }, { skipSuccessMessage: true });
// after defHttp.get<void>({ url: adminPath + '/tpl/delete', params }, { skipSuccessMessage: true });
// #12 src/plat/api/case/caseApi.ts:166
// before defHttp.delete<void>({ url: adminPath + '/case/delete', params: { id } });
// after defHttp.get<void>({ url: adminPath + '/case/delete', params: { id } });
// #13 src/trans/api/transApi.ts:68
// before defHttp.delete<void>({ url: adminPath + '/trans/cashKey/delete', params: { id } });
// after defHttp.get<void>({ url: adminPath + '/trans/cashKey/delete', params: { id } });
// #14 src/trans/api/transApi.ts:88
// before defHttp.delete<void>({ url: adminPath + '/trans/financialKey/delete', params: { id } });
// after defHttp.get<void>({ url: adminPath + '/trans/financialKey/delete', params: { id } });
// #15 src/trans/api/transApi.ts:108
// before defHttp.delete<void>({ url: adminPath + '/fixedDepositKey/delete', params: { id } });
// after defHttp.get<void>({ url: adminPath + '/fixedDepositKey/delete', params: { id } });
| api 函数 | 调用方 |
|---|---|
updateSessionTitle / deleteSession / togglePinSession / deleteMessage / toggleStarMessage |
src/ai/store/chatStream.ts |
modelApi.updateModel(豁免项) |
src/ai/components/ModelFormModal.vue:82 |
modelApi.setDefaultModel / deleteModel |
src/ai/views/aiModel/index.vue |
deleteInsightSession |
src/graph/insight/hooks/useInsightStream.ts |
deletePersonBasicInfo / remPersonFromGroup |
src/case/views/dm/portrait.vue |
tplDelete |
src/case/views/data/index.vue |
deleteById(案件) |
src/plat/views/case/case.vue |
deleteCashKey |
src/trans/views/cashTrans/index.vue |
deleteFinancialKey |
src/trans/views/financialWealth/index.vue |
deleteFixedDepositKey |
src/trans/views/fixedDeposit/index.vue |
src/ai/api/chatApi.ts、src/ai/api/modelApi.ts、src/graph/insight/api.ts、src/person/api/personApi.ts、src/plat/api/tpl/tplApi.ts、src/plat/api/case/caseApi.ts、src/trans/api/transApi.ts。
封装工具文件 src/ai/api/http.ts、src/core/utils/http/axios/Axios.ts、src/core/utils/http/axios/index.ts 不在改动清单内。
AgentModelController#updateModel(唯一带 body 的 PUT)AgentModelController.java:56:@PutMapping("/{id}"),形参含 @Valid @RequestBody UpdateModelDTO → 命中 B 类豁免,保持 PUT + @RequestBody 原样;src/ai/api/modelApi.ts:27:aiHttp.putJson 保持不动;@DeleteMapping 为 0、@PutMapping 残留 1 处,此条为豁免白名单,§6 的 grep 校验需排除它。@GetMapping 接口(含 InsightController#listMessages、DataProfileController#getTransOtherNamePage、TableInfoController#page、SpecialDateController#delete 这类 Query/DTO 对象形参的 GET);@PostMapping 接口。src/person/api/personApi.ts:79 的 deleteSpecialDateConfig 用 defHttp.delete 调用 /sdc/delete,后端 SpecialDateController.java:39 是 @GetMapping —— 方法不匹配(现网表现为 405)。后端是 GET,命中 A 类豁免,本次不动;前端调用方式本批也不动,仅记录。
@GetMapping、也没有 @RequestBody,命中任一即跳过。@GetMapping(§2)+ 清理 5 个无用 DeleteMapping import。AgentChatController#deleteSession、InsightController#deleteSession 路径加 /delete(§1.5)。@DeleteMapping 为 0、@PutMapping 仅剩 §4.1 白名单 1 处。git diff 中只应出现 §2 的后端文件 + §3.5 的 7 个前端文件;封装工具文件、47 个 GET 接口、82 个 POST 接口一个都不能被改到。编译 / 类型
mvn -q -pl ai-server compile,零错误。vue-tsc --noEmit + pnpm build,零错误。dist,否则 api 层改动不生效。冒烟(浏览器逐一操作)
| # | 功能 | 页面 | 预期 |
|---|---|---|---|
| 1 | 会话重命名 | AI 数据分析左侧会话条 | 标题更新,Network 显示 GET |
| 2 | 删除会话 | 同上 | 会话消失 |
| 3 | 会话置顶/取消 | 同上 | 排序变化 |
| 4 | 删除消息 | 对话区消息悬浮菜单 | 消息消失 |
| 5 | 消息收藏/取消 | 同上 | 星标切换 |
| 6 | 删除模型 | AI 模型管理 | 列表刷新(GET) |
| 7 | 设为默认模型 | AI 模型管理 | 默认标记切换(GET) |
| 8 | 编辑模型(豁免项,保持 PUT) | AI 模型管理 - 编辑弹窗 | 保存成功,Network 仍为 PUT |
| 9 | 删除研判会话 | 对象关系分析 - 历史 | 会话消失 |
| 10 | 删除人员 | 人物画像 case/views/dm/portrait.vue |
人员移除 |
| 11 | 分组移除成员 | 同上 | 成员移除 |
| 12 | 删除模板 | 数据管理 case/views/data/index.vue |
模板消失 |
| 13 | 删除案件 | 案件管理 plat/views/case/case.vue |
案件消失 |
| 14 | 删除现金关键字 | 资金交易 - 现金交易 | 列表刷新 |
| 15 | 删除金融理财关键字 | 资金交易 - 金融理财 | 列表刷新 |
| 16 | 删除定期理财关键字 | 资金交易 - 定期理财 | 列表刷新 |
交叉确认(改造后已实测):
@DeleteMapping:0;@PutMapping:1(AgentModelController.java:56,白名单)。defHttp.delete / defHttp.put / aiHttp.deleteRaw / aiHttp.putRaw / aiHttp.delete:0;aiHttp.putJson:1(modelApi.ts:27,白名单)。src/ai/api/http.ts 与 src/core/utils/http/axios/*:零改动。编译 / 构建实测结果(2026-09-18 19:26 / 19:28)
mvn -pl ai-server compile:BUILD SUCCESS(686 个源文件,耗时 1m02s)。pnpm build:成功(vite build,耗时 1m39s,dist 已重新产出)。vue-tsc --noEmit:项目存在约 100+ 条存量类型错误(与本批改动无关,集中在 graph/views/graph/index.vue、case/views/dm/portrait.vue、otg/utils/timeSeriesJump.ts 等);本批改动的 7 个前端文件中没有新增错误,仅 person/api/personApi.ts:119(isShowLoading)一条既有报错,非本次改动行。改动文件清单(git diff --name-only,共 17 个)
后端 10 个:AgentChatController、AgentModelController、InsightController、PersonBasicInfoController、PersonGroupController、CaseInfoController、TableInfoController、CashKeyController、FinancialKeyController、FixedDepositKeyController。
前端 7 个:ai/api/chatApi.ts、ai/api/modelApi.ts、graph/insight/api.ts、person/api/personApi.ts、plat/api/case/caseApi.ts、plat/api/tpl/tplApi.ts、trans/api/transApi.ts。
beforeRequestHook(core/utils/http/axios/index.ts:147-156)对 GET 自动追加 _t 时间戳。/pbi/delete?personName=张三 走 URL 传参,依赖服务端 URI 编码 UTF-8(Spring Boot 3 默认),回归时确认中文姓名能正常删除。dist 未重新构建会导致改动看似未生效。AI_AGENT.md「接口方法规范」)PUT / DELETE / PATCH。@RequestBody → 必须 POST。@RequestBody 时:形参 > 3 → POST;≤ 3 → GET。@GetMapping 的接口、形参已带 @RequestBody 的接口,一律不再改造。src/core/utils/http/**、src/ai/api/http.ts)。