@RequestBody 缺失审计审计时间:2026-09-16 · 范围:
ai-server/src/main/java/**/*Controller.java(45 个 controller) 生成方式:脚本静态扫描后端映射注解与方法签名 + 交叉比对前端全部defHttpPOST 调用点
结论: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 |
content-type 是 application/x-www-form-urlencoded(core/utils/http/axios/index.ts),
只有 defHttp.postJson() 会显式设成 application/json 并把 data 作为 JSON 请求体发出。ModelAttributeMethodProcessor,只从 query string / form 字段绑定,
完全不会解析 JSON body。同类缺陷在本仓库已有先例并被修过:
/case/create、/case/open、/dm/preFile等(提交前用curl观察parameters={}→ 500)。
| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(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 |
| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(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 |
| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(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 |
| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(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 |
| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(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 |
| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(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 |
| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(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 |
| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(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 |
| 位置 | 方法 | 路径 | 参数 |
|---|---|---|---|
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 |
/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:78ResidentPopulationController 只有类级 @RequestMapping("/rp")、没有任何端点方法,属空壳类(可删或待补)。SystemController/TowerController/GovernController/SearchController/CleanErrorLogController/AgentResultController/AgentPythonFileController/TransFastFundFlowController/ResidentPopulationController),本次审计不涉及。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={})。