controller-request-body-audit.md 21 KB

Controller 接口 @RequestBody 缺失审计

审计时间:2026-09-16 · 范围:ai-server/src/main/java/**/*Controller.java(45 个 controller) 生成方式:脚本静态扫描后端映射注解与方法签名 + 交叉比对前端全部 defHttp POST 调用点

〇、修复记录(2026-09-16 当日完成)

结论:76 个缺注解端点已全部处理完毕;复扫 broken = 0、missingBindingAnnotation = 0。 下方第一~八节保留的是修复前的审计状态,作为问题清单与判定依据留档。

项 内容
改动文件 32 个 controller + 新增 1 个 DTO(common/model/person/dto/DeletePersonGroupDTO.java)
改动内容 74 个 POJO 参数前加 @RequestBody;/pg/delete 改 @RequestBody DeletePersonGroupDTO;statSecondCallNight 的无效 MyBatis @Param("query") 替换为 @RequestBody
清理 删除被替换后失效的 import org.apache.ibatis.annotations.Param(CallNightController);删除 4 处与通配符 import 重复的显式 RequestBody import;顺带删除 3 个 controller 中未使用的 org.apache.ibatis.annotations.Delete import
结构校验 脚本比对修复前后:映射注解(URL)零改动、方法签名除 @RequestBody 外零改动、新增行仅 75 条签名行 + 32 条 import
编译 mvn -pl ai-server clean compile → BUILD SUCCESS(621 源文件)
复扫 writeEndpoints=98 / missingBindingAnnotation=0 / broken=0 / annotated=97 + multipart=1
回退方式 32 个文件中有 31 个改动前与 HEAD 一致 → git checkout -- <文件> 可完整回退;DataProfileController.java 修复前已有他人/既有本地改动(import 由 4 行显式改为 annotation.* 通配符),git checkout 会连带丢弃该改动,回退请用备份副本

尚未做:运行期端到端验证(起后端发 JSON body 请求确认筛选条件真正生效)。静态层面已闭环。

一、结论摘要

指标 数量
Controller 文件 45(其中 36 个含 POST/PUT 端点,9 个仅 GET,1 个为空壳)
写端点(POST/PUT/PATCH)总数 98
缺 @RequestBody 的端点 76
├ 其中已确认有问题(前端以 JSON body 调用) 75
└ 其中暂无前端调用方(需人工确认) 1
已正确(含 @RequestBody) 21
multipart 上传端点(写法正确) 1

二、判定标准(为什么是「有问题」而不是「风格问题」)

  1. 前端 axios 默认 content-type 是 application/x-www-form-urlencoded(core/utils/http/axios/index.ts), 只有 defHttp.postJson() 会显式设成 application/json 并把 data 作为 JSON 请求体发出。
  2. 后端方法参数不加注解时,Spring MVC 走 ModelAttributeMethodProcessor,只从 query string / form 字段绑定, 完全不会解析 JSON body。
  3. ⇒ 前端发 JSON body + 后端参数无注解 = body 被丢弃,参数对象所有字段为 null。 表现:筛选条件(号码/时间/分页)静默失效、返回全量或空数据;个别场景直接 500/NPE。

同类缺陷在本仓库已有先例并被修过:/case/create、/case/open、/dm/preFile 等(提交前用 curl 观察 parameters={} → 500)。

三、确认有问题的端点(75 个,按模块分组)

通信分析(7)

# 位置 方法 路径 缺注解的参数 前端调用点(postJson)
1 controller/CallContinuousController.java:34 statFirstCallContinuous /call/continuous/statFirstCallContinuous CallContinuousQuery query api/callApi.ts:14
2 controller/CallContinuousController.java:46 statSecondCallContinuous /call/continuous/statSecondCallContinuous CallContinuousQuery query api/callApi.ts:23
3 controller/CallNightController.java:37 statFirstCallNight /call/night/statFirstCallNight CallNightQuery query api/callApi.ts:34
4 controller/CallNightController.java:49 statSecondCallNight /call/night/statSecondCallNight @Param("query") CallNightQuery query api/callApi.ts:40
5 controller/CallRecordController.java:33 getCallRecord /cr/getCallRecord CallRecordQuery query api/callApi.ts:62
6 controller/CallSensitiveController.java:35 statFirstCallSensitive /call/sensitive/statFirstCallSensitive CallSensitiveQuery query api/callApi.ts:48
7 controller/CallSensitiveController.java:47 statSecondCallSensitive /call/sensitive/statSecondCallSensitive CallSensitiveQuery query api/callApi.ts:54

数据治理(6)

# 位置 方法 路径 缺注解的参数 前端调用点(postJson)
1 controller/GovernTreeController.java:58 getTreeTransPersonPage /gt/getTreeTransPersonPage GovernTreeQuery dto govern/governApi.ts:117
2 controller/GovernTreeController.java:70 getTreeTransBankPage /gt/getTreeTransBankPage GovernTreeQuery dto govern/governApi.ts:123
3 controller/GovernTreeController.java:82 getTreeCallPersonPage /gt/getTreeCallPersonPage GovernTreeQuery dto govern/governApi.ts:129
4 controller/GovernTreeController.java:94 getTreeCallOperPage /gt/getTreeCallOperPage GovernTreeQuery dto govern/governApi.ts:135
5 controller/GovernTreeController.java:106 getTreeCallPersonUseOpenInfoPage /gt/getTreeCallPersonUseOpenInfoPage GovernTreeQuery dto govern/governApi.ts:141
6 controller/GovernTreeController.java:118 getTreeCallOperUseOpenInfoPage /gt/getTreeCallOperUseOpenInfoPage GovernTreeQuery dto govern/governApi.ts:147

关系图谱(4)

# 位置 方法 路径 缺注解的参数 前端调用点(postJson)
1 controller/GraphController.java:39 graph /graph/view GraphQuery query api/analysis.ts:1249
2 controller/GraphController.java:51 transDetail /graph/transDetail GraphTransDetailQuery query api/analysis.ts:1264
3 controller/GraphController.java:63 callDetail /graph/callDetail GraphCallDetailQuery query api/analysis.ts:1277
4 controller/GraphController.java:68 nodeDetail /graph/nodeDetail GraphCallDetailQuery query api/analysis.ts:1289

时空/轨迹基础(5)

# 位置 方法 路径 缺注解的参数 前端调用点(postJson)
1 controller/SpecialDateController.java:26 create /sdc/create SpecialDateRecord sdr api/personApi.ts:61
2 controller/SpecialDateController.java:32 update /sdc/update SpecialDateRecord sdr api/personApi.ts:70
3 controller/TimeSeriesController.java:22 getTimeSeries /otg/timeSeries/list TimeSeriesQuery query api/otgApi.ts:54
4 controller/TimeSeriesController.java:27 detailTimeSeries /otg/timeSeries/detailTimeSeries TimeSeriesQuery query api/otgApi.ts:65
5 controller/TimeSeriesController.java:32 jumpTimeSeries /otg/timeSeries/jump TimeSeriesQuery query api/otgApi.ts:76

对象画像(15)

# 位置 方法 路径 缺注解的参数 前端调用点(postJson)
1 controller/DataProfileController.java:52 callOftenTop10 /dp/callOftenTop10 CallOftenTop10Query query api/dpApi.ts:51
2 controller/DataProfileController.java:65 callStatStation /dp/callStatStation CallStatStationQuery query api/dpApi.ts:57
3 controller/DataProfileController.java:78 getCallRecordSummary /dp/getCallRecordSummary CallRecordSummaryQuery query api/dpApi.ts:63
4 controller/DataProfileController.java:90 getCallOperPhoneInfo /dp/getCallOperPhoneInfo CallOperPhoneInfoQuery query api/dpApi.ts:69
5 controller/DataProfileController.java:153 getTransBankCardInfo /dp/getTransBankCardInfo TransBankCardInfoQuery query api/dpApi.ts:95
6 controller/DataProfileController.java:165 transAmountTrendYM /dp/transAmountTrendYM TransTrendQuery query api/dpApi.ts:107
7 controller/DataProfileController.java:177 transAmountTrendY /dp/transAmountTrendY TransTrendQuery query api/dpApi.ts:113
8 controller/IntimacyController.java:32 update /intimacy/modify List<Intimacy> intimacyList api/personApi.ts:43
9 controller/PersonBasicInfoController.java:24 create /pbi/create PersonBasicInfoDTO dto api/personApi.ts:90
10 controller/PersonBasicInfoController.java:46 update /pbi/update PersonBasicInfoDTO dto api/personApi.ts:108
11 controller/PersonBasicInfoController.java:57 personOrder /pbi/personOrder List<PersonBasicInfo> list api/personApi.ts:141
12 controller/PersonGroupController.java:31 create /pg/create PersonGroup personGroup api/personApi.ts:160
13 controller/PersonGroupController.java:42 update /pg/update PersonGroup personGroup api/personApi.ts:169
14 controller/PersonGroupController.java:53 delete /pg/delete Long id api/personApi.ts:178
15 controller/PersonGroupController.java:65 addPerson /pg/addPerson AddPersonGroupDTO dto api/personApi.ts:187

平台(表/案件/系统)(2)

# 位置 方法 路径 缺注解的参数 前端调用点(postJson)
1 controller/TableInfoController.java:72 create /tpl/create TableInfo tableInfo tpl/tplApi.ts:63
2 controller/TableInfoController.java:81 update /tpl/update TableInfo tableInfo tpl/tplApi.ts:69

活动轨迹(15)

# 位置 方法 路径 缺注解的参数 前端调用点(postJson)
1 controller/ExpressInfoController.java:32 statFirstExpressInfo /expressInfo/statFirstExpressInfo ExpressInfoQuery query api/trackApi.ts:51
2 controller/ExpressInfoController.java:43 statSecondExpressInfo /expressInfo/statSecondExpressInfo ExpressInfoQuery query api/trackApi.ts:60
3 controller/TrackCellTowerController.java:32 statFirstTrackCellTower /track/cellTower/statFirstTrackCellTower TrackCellTowerQuery query api/trackApi.ts:71
4 controller/TrackCellTowerController.java:44 statSecondTrackCellTower /track/cellTower/statSecondTrackCellTower TrackCellTowerQuery query api/trackApi.ts:77
5 controller/TrackEnLocalController.java:35 statFirstTrackEnLocal /track/enLocal/statFirstTrackEnLocal TrackEnLocalQuery query api/trackApi.ts:85
6 controller/TrackEnLocalController.java:41 statSecondTrackEnLocal /track/enLocal/statSecondTrackEnLocal TrackEnLocalQuery query api/trackApi.ts:94
7 controller/TrackMeetController.java:33 statFirstTrackMeet /track/meet/statFirstTrackMeet TrackMeetQuery query api/trackApi.ts:112
8 controller/TrackMeetController.java:45 statSecondTrackMeet /track/meet/statSecondTrackMeet TrackMeetQuery query api/trackApi.ts:121
9 controller/TrackTogetherLiveController.java:36 statFirstTrackTogetherLive /track/togetherLive/statFirstTrackTogetherLive TrackTogetherLiveQuery query api/trackApi.ts:132
10 controller/TrackTogetherLiveController.java:41 statSecondTrackTogetherLive /track/togetherLive/statSecondTrackTogetherLive TrackTogetherLiveQuery query api/trackApi.ts:141
11 controller/TrackTogetherLiveController.java:52 hotelStayInfoDetail /track/togetherLive/hotelStayInfoDetail TogetherLiveDetailQuery togetherLiveDetailQuery api/trackApi.ts:153
12 controller/TrackTogetherLiveController.java:64 togetherLiveInfoDetail /track/togetherLive/togetherLiveInfoDetail TogetherLiveDetailQuery togetherLiveDetailQuery api/trackApi.ts:165
13 controller/TrackTogetherTravelController.java:33 statTogetherTravel /track/togetherTravel/statTogetherTravel TrackTogetherTravelQuery query api/trackApi.ts:179
14 controller/TrackTogetherTravelController.java:38 statSecondTogetherTravel /track/togetherTravel/statSecondTogetherTravel TrackTogetherTravelQuery query api/trackApi.ts:188
15 controller/TrackTogetherTravelController.java:43 statThreeTogetherTravel /track/togetherTravel/statThreeTogetherTravel TrackTogetherTravelQuery query api/trackApi.ts:200

交易分析(21)

# 位置 方法 路径 缺注解的参数 前端调用点(postJson)
1 controller/CashKeyController.java:44 create /trans/cashKey/createOrUpdate TransCashKey transCashKey api/transApi.ts:62
2 controller/FinancialKeyController.java:38 createOrUpdate /trans/financialKey/createOrUpdate TransFinancialKey transFinancialKey api/transApi.ts:82
3 controller/FixedDepositKeyController.java:40 createOrUpdate /fixedDepositKey/createOrUpdate TransFixedDepositKey transFixedDepositKey api/transApi.ts:102
4 controller/TransBigController.java:39 statFirstTransBig /trans/big/statFirstTransBig TransBigQuery query api/transApi.ts:128
5 controller/TransBigController.java:51 statSecondTransBig /trans/big/statSecondTransBig TransBigQuery query api/transApi.ts:134
6 controller/TransBigController.java:63 statThirdTransBig /trans/big/statThirdTransBig TransBigQuery query api/transApi.ts:140
7 controller/TransCardHoldController.java:55 statTogetherDoTrans /trans/cardHold/statTogetherDoTrans StatTogetherDoTransQuery query api/transApi.ts:206
8 controller/TransCardHoldController.java:75 statTransCardHold /trans/cardHold/statTransCardHold StatTransCardHoldQuery query api/transApi.ts:215
9 controller/TransCashFlowController.java:33 statFirstTransCashFlow /trans/cashFlow/statFirstTransCashFlow TransRecordSummaryQuery query api/transApi.ts:116
10 controller/TransContinuousController.java:34 statFirstTransContinuous /trans/continuous/statFirstTransContinuous TransContinuousQuery query api/transApi.ts:148
11 controller/TransContinuousController.java:46 statSecondTransContinuous /trans/continuous/statSecondTransContinuous TransContinuousQuery query api/transApi.ts:157
12 controller/TransFinancialController.java:31 statFirstTransFinancial /trans/financial/statFirstTransFinancial TransFinancialQuery query api/transApi.ts:265
13 controller/TransFixedDepositController.java:36 statFirstTransFixedDeposit /trans/fixedDeposit/statFirstTransFixedDeposit TransFixedDepositQuery query api/transApi.ts:273
14 controller/TransFixedDepositController.java:48 statSecondTransFixedDepositList /trans/fixedDeposit/statSecondTransFixedDepositList TransFixedDepositQuery query api/transApi.ts:282
15 controller/TransFrequencyController.java:33 statFirstTransFrequency /trans/frequency/statFirstTransFrequency TransFrequencyQuery query api/transApi.ts:226
16 controller/TransFundFlowController.java:31 getTransFundFlowPage /trans/fundsFlow/getTransFundFlowPage TransRecordQuery query api/transApi.ts:168
17 controller/TransFundFlowController.java:42 transFlowGraph /trans/fundsFlow/graph TransFlowGraphQuery query api/transApi.ts:177
18 controller/TransFundFlowController.java:53 transFlowTrace /trans/fundsFlow/trace TransFlowGraphQuery param api/transApi.ts:186
19 controller/TransRecordController.java:19 getTransRecord /trans/getTransRecord TransRecordQuery query api/transApi.ts:257
20 controller/TransSensitiveController.java:34 statFirstTransSensitive /trans/sensitive/statFirstTransSensitive TransSensitiveQuery query api/transApi.ts:237
21 controller/TransSensitiveController.java:46 statSecondTransSensitive /trans/sensitive/statSecondTransSensitive TransSensitiveQuery query api/transApi.ts:246

四、暂无前端调用方(1 个,需人工确认)

位置 方法 路径 参数
controller/TransCashFlowController.java:45 statTransCashCallBeforeAfterTimeLine /trans/cashFlow/statTransCashCallBeforeAfterTimeLine TransCashCallBeforeAfterQuery query

前端未在 ai-frontend/src/** 中找到调用点(可能:未接入、由旧页面/外部调用、或拼 URL 方式特殊)。 若确认前端会用 JSON body 调用,同样需要补 @RequestBody。

五、特殊修法(不能简单加注解)

端点 现状 问题 建议
POST /pg/delete(PersonGroupController:53) 后端 delete(Long id),前端 body { id } 直接给 Long 加 @RequestBody 会变成"JSON 对象 → Long"反序列化失败(400) 前端改 params: { id } + 后端 @RequestParam Long id;或新增 IdDTO 用 @RequestBody
POST /intimacy/modify(IntimacyController:32) 参数 List<Intimacy>,前端发数组 需 @RequestBody List<Intimacy>(数组体) 加 @RequestBody 即可,字段与前端 IntimacyConfigDTO 兼容
POST /pbi/personOrder(PersonBasicInfoController:57) 参数 List<PersonBasicInfo>,前端发数组 同上 加 @RequestBody
POST /call/night/statSecondCallNight(CallNightController:49) 参数写成 @Param("query") CallNightQuery query @Param 是 MyBatis 注解,在 controller 上无效,仍属"无绑定注解" 去掉 @Param 换 @RequestBody

六、写法正确的对照(21 个 + 1 个 multipart,供参照)

  • /chat/sessions —— controller/AgentChatController.java:35
  • /chat/sessions/{sessionId}/title —— controller/AgentChatController.java:59
  • /chat/sessions/{sessionId}/pin —— controller/AgentChatController.java:75
  • /chat/messages —— controller/AgentChatController.java:91
  • /chat/messages/{messageId}/star —— controller/AgentChatController.java:107
  • /chat/stream —— controller/AgentChatController.java:129
  • /models —— controller/AgentModelController.java:48
  • /models/{id} —— controller/AgentModelController.java:56
  • /models/{id}/default —— controller/AgentModelController.java:74
  • /dm/preFile —— controller/DmController.java:57
  • /dm/rawPreview —— controller/DmController.java:93
  • /dm/doClean —— controller/DmController.java:104
  • /dm/getFiles —— controller/DmController.java:139
  • /dm/deletedFiles —— controller/DmController.java:149
  • /dm/saveGovernCon —— controller/DmController.java:168
  • /gt/treeTablePage —— controller/GovernTreeController.java:46
  • /dp/transOfPersons —— controller/DataProfileController.java:117
  • /dp/getTransRecordSummary —— controller/DataProfileController.java:129
  • /case/create —— controller/CaseInfoController.java:50
  • /case/updatePwd —— controller/CaseInfoController.java:73
  • /case/open —— controller/CaseInfoController.java:85
  • /dm/preFileUpload(multipart,写法正确)—— controller/DmController.java:78

七、其它发现

  • ResidentPopulationController 只有类级 @RequestMapping("/rp")、没有任何端点方法,属空壳类(可删或待补)。
  • 9 个 controller 只有 GET 端点(SystemController/TowerController/GovernController/SearchController/CleanErrorLogController/AgentResultController/AgentPythonFileController/TransFastFundFlowController/ResidentPopulationController),本次审计不涉及。
  • AI Agent 模块(AgentChatController/AgentModelController/DmController)此前已补过注解,本次复扫全部通过。

八、修复建议(已于当日执行完毕,见第〇节)

对 75 个端点:给唯一的 POJO/实体参数加 @RequestBody(import org.springframework.web.bind.annotation.RequestBody;), 属机械改动、可用脚本批量处理;改完 mvn -pl ai-server clean compile 通过即可。 /pg/delete 与 /call/night/statSecondCallNight 需按上表特殊处理。

验证方式:起后端后对 1~2 个端点发 JSON body 请求,确认筛选条件生效(对照今天的日志里是否出现 parameters={})。