本文引用的文件
本文面向后端接口使用者、前端开发者和数据分析人员,系统化说明 GraphController 暴露的图谱与图表相关 REST 接口。内容覆盖:
与图谱与图表接口直接相关的代码主要分布在以下位置:
ai-server/src/main/java/com/zsjz/ai/module/graph/controller/GraphController.javaai-server/src/main/java/com/zsjz/ai/module/graph/service/GraphService.javaGraphQuery、GraphTransDetailQuery、GraphCallDetailQueryGraphHisai-electron/frontend/src/graph/api/analysis.ts前端图谱页面:ai-electron/frontend/src/graph/views/graph/index.vue
graph TB
FE["前端页面<br/>graph/index.vue"] --> API_TS["前端 API 封装<br/>analysis.ts"]
API_TS --> CTRL["后端控制器<br/>GraphController"]
CTRL --> SVC["后端服务<br/>GraphService"]
SVC --> MAPPER["数据库访问层"]
SVC --> ENT_TRANS["交易记录<br/>TransRecord"]
SVC --> ENT_CALL["通话记录<br/>CallRecord"]
SVC --> ENT_HIS["图谱历史<br/>GraphHis"]
图示来源
章节来源
/graph/* REST 接口,负责接收请求参数并返回统一响应体。章节来源
GraphController 作为统一入口,不直接处理复杂业务,而是委托 GraphService。图谱生成过程会构造 SQL,通过临时表或子查询聚合交易、通话、其他关系,最终返回节点集合与边集合。前端 analysis.ts 将业务表单字段转换为后端期望的 GraphViewQuery 结构,并调用对应接口。图谱页面 index.vue 负责组合 UI 行为,例如打开分析条件弹窗、切换图谱画布、保存历史快照。
sequenceDiagram
participant User as "用户"
participant Page as "graph/index.vue"
participant Api as "analysis.ts"
participant Ctrl as "GraphController"
participant Svc as "GraphService"
participant DB as "数据库"
User->>Page: "点击生成关系图谱"
Page->>Api: "调用 fetchGraphAnalysis"
Api->>Ctrl: "POST /graph/view"
Ctrl->>Svc: "graph(query)"
Svc->>DB: "执行图谱聚合 SQL"
DB-->>Svc: "边列表 edgeList"
Svc-->>Ctrl: "Map{nodeList, edgeList}"
Ctrl-->>Api: "Result<Map>"
Api-->>Page: "标准化后的 dx/gx"
Page->>Page: "渲染 AntV G6/X6 图谱"
图示来源
/graphResult 包裹,前端 normalizeGraphAnalysisResponse 会从 response.data 或外层 data 中解析图谱数据。code 表示业务成功;失败时可能抛出服务端异常或返回错误码。POST /graph/viewContent-Type: application/jsontype:关系类型数组,取值包括交易类 101、102、103,以及通话类 201、202、203。cards:卡号列表。startMoney、endMoney:交易金额起止值。callNum:通话号码。GraphViewQuery 传递的条件字段,如人员姓名、身份证号、时间范围等。Result<Map<String, Object>>,前端标准化后为 { code, msg, data: { dx: 节点数组, gx: 边数组 } }。错误行为:
未传入 type 时,返回空图谱结果。
flowchart TD
Start(["进入 /graph/view"]) --> CheckType["校验 type 是否为空"]
CheckType -->|为空| Empty["返回空图谱"]
CheckType -->|非空| BuildSQL["构造图谱聚合 SQL"]
BuildSQL --> QueryDB["执行数据库查询"]
QueryDB --> CountEdge{"边数量是否超过 10000"}
CountEdge -->|是| Error["抛出数据量过大异常"]
CountEdge -->|否| Assemble["组装 nodeList 与 edgeList"]
Assemble --> Return["返回 Result<Map>"]
图示来源
章节来源
POST /graph/transDetailpersonCardNo:本方卡号。otherCardNo:对方卡号。lx:交易方向或类别。jdlx:借贷类型,例如收入、支出。otherName:交易对方名称。ext1:交易摘要。transAmountSymbol、transAmount:金额比较符号与金额值。page、limit。Result<Page<TransRecord>>,即分页的交易记录。章节来源
POST /graph/callDetailpersonPhone:本方号码。otherPhone:对方号码。node、clazz:图谱节点标识与分类。transAmountSymbol、transAmount:金额比较符号与金额值。page、limit。Result<Page<CallRecord>>,即分页的通话记录。章节来源
POST /graph/nodeDetailResult<Map<String, Object>>,具体结构由服务层决定,通常包含节点维度可展开的明细或统计信息。章节来源
GET /graph/graphHisResult<List<GraphHis>>,每个记录包含 id、graphName、path。章节来源
GET /graph/createGraphHisgraphHisName:图谱记录名称。Result<GraphHis>,返回创建的记录。章节来源
GET /graph/deleteGraphHisid:图谱历史记录 ID。Result<Void>。章节来源
GET /graph/history/{id}/contentid:图谱历史记录 ID。Result<String>,返回图谱快照的 JSON 字符串。章节来源
POST /graph/history/{id}/contentid:图谱历史记录 ID。Result<Void>。章节来源
图谱的核心实体关系如下:
GraphViewQuery 中的扩展字段驱动。边:
其他关系边:由服务层动态拼接 SQL 生成。
erDiagram
PERSON {
string name
string card_no
string identity_code
}
ACCOUNT {
string card_no
string owner_id
}
CALL_RECORD {
string from_phone
string to_phone
datetime call_time
}
TRANS_RECORD {
string from_card
string to_card
decimal amount
datetime trans_time
}
GRAPH_NODE {
string node
string clazz
string nodecn
}
GRAPH_EDGE {
string node1
string node2
string clazz
string mc
number money
}
PERSON ||--o{ ACCOUNT : "拥有"
ACCOUNT ||--o{ TRANS_RECORD : "发起或接收"
CALL_RECORD }o--|| CALL_RECORD : "相互联系"
GRAPH_NODE ||--o{ GRAPH_EDGE : "被引用"
图示来源
前端在图谱与图表场景中通常采用三种渲染方案:
ECharts:用于辅助分析图表,如资金流向、通话频次、时间趋势等,通常在图谱侧边栏或独立图表区域展示。
graph TB
View["graph/index.vue"] --> AnalysisApi["analysis.ts"]
View --> G6X6["AntV G6/X6 渲染引擎"]
View --> RelationGraph["Relation Graph 业务视图"]
View --> ECharts["ECharts 辅助图表"]
AnalysisApi --> Controller["/graph/* 接口"]
图示来源
章节来源
/graph/history/{id}/content 保存为 JSON 字符串,适合再次导入或离线分析。章节来源
生成关系图谱:
curl -X POST "http://your-host/admin/graph/view" \
-H "Content-Type: application/json" \
-d '{
"type": [101, 201],
"cards": ["卡号A", "卡号B"],
"startMoney": "1000",
"endMoney": "100000",
"callNum": "13800000000"
}'
查询交易明细:
curl -X POST "http://your-host/admin/graph/transDetail" \
-H "Content-Type: application/json" \
-d '{
"personCardNo": "卡号A",
"otherCardNo": "卡号B",
"page": 1,
"limit": 20
}'
查询通话明细:
curl -X POST "http://your-host/admin/graph/callDetail" \
-H "Content-Type: application/json" \
-d '{
"personPhone": "13800000000",
"otherPhone": "13900000000",
"page": 1,
"limit": 20
}'
读取图谱历史快照:
curl -X GET "http://your-host/admin/graph/history/1/content"
保存图谱历史快照:
curl -X POST "http://your-host/admin/graph/history/1/content" \
-H "Content-Type: application/json" \
-d '{"nodes":[],"edges":[]}'
生成图谱:
import { fetchGraphAnalysis } from '@/graph/api/analysis';
const result = await fetchGraphAnalysis({
respondents: [{ id: '1', name: '张三' }],
tradeMode: 'trade',
communicationMode: 'contact',
queryTime: ['2025-01-01', '2025-12-31'],
});
// result.data.dx 为节点,result.data.gx 为边
查询交易明细:
import { fetchGraphTransDetail } from '@/graph/api/analysis';
const page = await fetchGraphTransDetail({
personCardNo: '卡号A',
page: 1,
limit: 20,
});
查询通话明细:
import { fetchGraphCallDetail } from '@/graph/api/analysis';
const page = await fetchGraphCallDetail({
personPhone: '13800000000',
page: 1,
limit: 20,
});
保存图谱历史:
import { createGraphHistory, saveGraphHistoryContent } from '@/graph/api/analysis';
const history = await createGraphHistory({ graphHisName: '张三关系图' });
await saveGraphHistoryContent(history.id, snapshotJson);
章节来源
type。如果 type 为空,服务层会直接返回空图谱。fetchGraphAnalysis 在未获取到对象名称时会抛错,要求先选择人员或实体。dx/gx 或整体 data 为空。章节来源
章节来源
/graph/history/{id}/content 的读写。确认:
章节来源
Page 对象。若前端解析失败,检查:
page、limit 是否为有效数字;章节来源
GraphController 提供了图谱生成、明细分页、节点详情和历史快照管理能力。其核心设计是:前端以业务条件驱动 GraphQuery,后端通过服务层构造 SQL 并返回节点与边;前端基于 AntV G6/X6 或 Relation Graph 渲染关系图,并使用 ECharts 补充统计分析。为避免大数据量问题,应严格限制图谱规模、使用分页与过滤、并在前端进行合理的渲染优化。导出功能以 JSON 快照为主,复杂格式应在前端处理。遇到问题时,优先从输入条件、边数量上限、分页结构和历史快照读写链路入手排查。