geometry-read-model-sources.md 28 KB

后端几何读模型源核查

本报告仅依据 E:\pipe-ner-server 当前可读源码、既有 SQL 和第一方设计说明进行静态核查。指定目标文件经两次路径发现确认原先不存在,因此本次新建;未覆盖旧研究。使用 research 技能与默认运行模型;技能要求的嵌套后台代理被工具深度上限拒绝,研究由本委派代理直接完成。未修改后端;未运行构建、测试、服务、HTTP 或浏览器。由于用户约束及工作区规则,已跳过 build/debug 验证。

“源码事实”不等于已部署数据库事实:本次未连接数据库,不能确认迁移是否落库、现网字典值、对象数量或坐标质量。下文建议均不是现有接口已承诺的新契约。

1. 可直接采用的结论

  • 三类几何源分别是统一管网线段、燃气管点、窨井台账;它们具有真实 ID 和坐标字段,但没有坐标可信校核状态/来源/人员/时间字段。不能因为经纬度不为空、范围合法、WGS84 注释或已有 GIS 返回 Feature,就把 coordinateVerified 置为 true。管网实体:23–96、燃气管点实体:22–89、窨井实体:22–76。
  • 三套数字/类型域不能复用:MonitorPoint.pointType 为 1供水/2排水/3燃气;PipeNetworkBase.networkType 的通用 GIS 口径为字符串 0燃气/1排水/2供水;GasPipePoint.pointType 是 String 设施类别,源码只列“阀门/调压/计量/阴极保护/弯头/三通/其它”,未找到其真实存储编码字典。监测点枚举:11–28、通用 GIS:40–63、燃气管点类型:35–48。
  • 当前业务驾驶舱 map adapter 没有接入这三种设施几何,只组合监测点、设备与设备类型;监测点/设备均显式传 coordinateVerified=false。现有快照也只有 types / monitoringPoints / smartDevices,不能声称已有 pipeLines/gasPipePoints/manholes 读模型。业务 map adapter:198–274、快照顶层:9–21。

2. 三种几何实体、ID 与 networkId 语义

几何源 权威身份与关联 几何字段 删除/其它边界
PipeNetworkBase app_user.pipe_network_base;networkId 对应 network_id,String,ASSIGN_UUID;networkCode 是设施编码,不能当关联主键 startLongitude/startLatitude/endLongitude/endLatitude 四个 BigDecimal;字段注释明确 WGS84;只能证明一个两端点线段,没有中间折点或拓扑 delFlag String,@TableLogic(0→2);业务 status 为独立 String 字段
GasPipePoint app_user.gas_pipe_point;pointId Long 自增;networkId String 注释“所属管线ID”;另有冗余 networkName longitude/latitude BigDecimal;实体注释没有声明具体 CRS @TableLogic(0→2);业务 status 注释 0正常/1异常/2停用,与 delFlag=2 含义不同
ManholeBase app_user.manhole_base;manholeId String UUID;networkId String 注释“关联管网设施ID” longitude/latitude BigDecimal;实体注释没有声明具体 CRS @TableLogic(0→2);没有 pointType/行业字段,业务 status 独立

表中每行依据:管网身份/类型:23–37、管网状态/删除/坐标:61–95;管点身份/关联/类型/坐标:22–48、管点状态/删除:66–88;窨井身份/关联/坐标:22–45、窨井状态/删除:59–75。

GasPipePoint.networkId → PipeNetworkBase.networkId 有实际使用证据:设备全量 VO 读取管点的 networkId、对统一管网做 selectBatchIds,再按 point.getNetworkId() 匹配管网并补设施字段。因此它表示所属设施记录 ID,不是网络集合、设备 ID、监测点 ID,也不是 networkCode。设备组装关联:1021–1044、补管点/管网字段:1079–1096。

ManholeBase.networkId 的“关联统一设施”只能由实体注释确认;当前窨井查询/保存服务未 join 管网或检查 networkId 是否存在。燃气管点保存/修改也只检查自身编码及自身 ID,不检查所属管线存在、是否燃气或是否已删除。管网删除服务仅检查管网存在后删除,未检查管点/窨井反向引用。本次没有足够 DDL 证据断言数据库有无外键或级联约束,应把悬空关联作为读模型需要降级的情况。窨井服务:23–64、管点写入检查:51–78、管网删除:123–156。

监测点关系与设施关系须分别建模:equipment_point_rel.pointId 是 String 监测点 ID;gas_pipe_point_device_rel.pointId 是 Long 管点 ID;窨井关系使用 manholeId String。前者实体没有逻辑删除字段,后两者有 @TableLogic(0→2)。不能把三个表按相同字段名合并为一种点位关系。监测点关系:20–38、燃气管点关系:21–46、窨井关系:21–46。

3. pointType 真实字典与源码/旧说明冲突

3.1 MonitorPoint.pointType 已有第一方枚举

当前实体将 pointType 声明为 Integer,使用 @TableField(updateStrategy=ALWAYS),没有 exist=false;枚举是 WATER_SUPPLY(1) / DRAINAGE(2) / GAS(3),isValid(null)=true。保存、批量保存、更新均使用枚举校验;列表筛选按整数精确匹配。null 是源码允许的未分类状态,枚举没有 4窨井或 UNKNOWN 数字值。监测点实体:38–40、枚举:11–28、列表/新增:41–80、批量/更新:84–116、校验调用:346–349。

当前 map adapter 注释仍说 monitor_point 无行业/类型列;旧后端说明还说 point_type 不存在且兼容字段 exist=false。这些陈述与当前实体不一致,不能把旧说明当作当前源码结论。实际 adapter 也未读取 getPointType(),仅在关联设备类型集合恰好一个时赋 typeCode;无设备或混合类型仍为 null。后续若打算用自有 pointType 给空点确定行业,需另行决定读模型契约,并先确认部署 schema;本次静态核查不能证明数据库已加入该列。旧说明:195–199、adapter 旧注释:59–61、adapter 实际推导:215–243。

3.2 GasPipePoint.pointType 不能编造编码

它是 String;DTO 也是 String;分页 wrapper 直接按原值 .eq;保存/更新没有类型枚举白名单检查。实体中文注释只给类别名称,无法据此证明存储值是 0..6、英文码还是中文文本。本次对后端 java/sql/xml 及相关 vue/js/ts/json/md 检索没有发现燃气管点类型种子/枚举;没有读取 live sys_dict_data。后续应保留 rawPointType,未知值展示原值/未分类,待真实字典来源确认后再映射,禁止把它套入 MonitorPointTypeEnum 或设备类型字典。管点实体:41–42、管点 DTO:20–24、查询:23–40、保存/更新:51–78。

4. 逻辑删除、选择查询及完整性

三种 mapper 均仅继承 MyBatis-Plus BaseMapper,服务继承 ServiceImpl;结合实体 @TableLogic(0→2),这些标准 list/getById/page/remove 路径的源码意图是只查询正常记录、执行逻辑删除。未运行 SQL,不能声称已验证运行时生成的 SQL。管网 mapper:7–9、管点 mapper:7–9、窨井 mapper:7–9。

  • 管网 /PipeNetworkBase/getList 返回 service.list();分页按 networkCode/name 模糊匹配、networkType/status 精确匹配;getOptions() 只选择 ID/name/code,不含任何坐标或 networkType,不能拿下拉列表当几何源。管网控制器:29–58、分页:42–60、选项:115–120。
  • 管点 /api/gas-pipe-point/list-by-network/{networkId} 只按 networkId 精确查询,按 pointCode 排序,不检查管网存在或有效,也不按业务 status 排除;分页可附 pointType/status;options() 同样只有 pointId/name/code,没有 geometry、networkId 或 pointType。管点控制器:65–76、管点服务:23–48。
  • 窨井 /api/manhole/list 明确返回全量 service.list(),可作为保留缺坐标对象的原始台账路径;分页只有 name/code/status 筛选,没有 networkId;getOptions() 只有 ID/name/code。窨井控制器:50–61、窨井服务:23–38。
  • 直接使用自定义 SQL 必须显式写正常记录条件;供水 GIS 的五类 select 与 overview 均写 del_flag='0'。不要假定任意手写 join 都得到 BaseMapper 的逻辑删除保障。供水 GIS mapper:4–43。

5. 业务 GIS 已有实现可以证明什么

5.1 通用 GIS:/api/gis

管网接口将 networkType 按标准字符串 0/1/2 与历史别名过滤;未知类型入参按原值精确匹配,不强制降到某个行业。未传类型时查询全部正常管网。仅四坐标非空就输出两端点 LineString,properties 保留 networkId/name/type/code;没有范围、零坐标、可信校核或线长检查。通用 GIS:35–104。

窨井接口只过滤缺经纬度对象,properties 有 manholeId/name/code/status,丢失 networkId;设备接口也只判空,虽然接收 equipmentTypeId,却没有将参数应用到查询/循环,实际 equipmentService.list()。这两个 GeoJSON 接口都未返回 coordinateValidation。窨井 GIS:113–138、设备 GIS:141–166。

该控制器没有 GasPipePoint 图层;燃气管点当前通过台账/list-by-network 取实体,不能把 /api/gis/equipments 当管点图层。通用 GIS 全控制器:24–168。

5.2 供水设施 GIS:/waterSupply/gis/map

正式支持 source/plant/pumpStation/pipe/user。管网 features 来自统一 pipe_network_base,SQL 要求 del_flag='0' AND network_type='2' 且四坐标非空;不会纳入通用 GIS 兼容的 water/WATER_SUPPLY/供水历史值。Service 输出 pipe:<network_id> 身份与 BigDecimal 两端点 LineString,坐标顺序固定 [longitude,latitude]。供水接口:22–43、管线 SQL:16–21、LineString/Feature:118–169。

overview 的 geoCompleteCount 只代表非空,不代表 VALID/verified;第一方规格明确“完整性只判空,不在后端校验范围或自动纠偏”。详情的 pipe 分支是直接 getById(id),没有重复 networkType='2' 约束,因此源码允许供水详情通过真实 ID 读到其它行业管网;应作为来源范围不一致风险记录,不能说已验证越权攻击。overview SQL:27–43、规格:197–202、详情:55–65。

供水设备 GIS 也仅按非空坐标过滤;名为 bdLon/bdLat 的字段由 fillGpsFields 直接复制原经纬度,并未进行坐标转换。字段名称不能证明 BD-09,不能在接入层再盲目转换。供水设备点位:173–203、GPS 字段填充:678–688。

5.3 排水还存在独立模型

PipeNetworkInfo 对应 app_user.psgw_pipe_network_info,networkType 是“管线/管点/排口”的形状类别;points 是 JSON 字符串,设备关联是逗号串。它不是统一 PipeNetworkBase,实体没有 delFlag/TableLogic,服务删除调用 BaseMapper.deleteById。本次没有建立该 JSON 的 CRS/结构/校核权威,不能把它自动并入本次两端点几何源或按 0→2 逻辑删除解读。排水实体:20–54、排水删除:68–96。

6. 可信校验状态与来源

CockpitCoordinateValidation 是只读响应结果,只有 state/reason/renderable/crs;不是持久化验证证据。快照的 coordinateVerified 是构造器布尔输入,也没有核验人、时间、来源、坐标版本或证明材料。验证器只能消费“外部已经可信的 boolean”,不能创造可信性。校验结果:3–19、快照点位:67–97、验证器:11–31。

输入/检查顺序 state reason renderable
coordinateVerified=false,优先于所有数值检查 UNVERIFIED UNVERIFIED_COORDINATE false
true 且缺经度/纬度 INVALID MISSING_LONGITUDE / MISSING_LATITUDE false
true 且经度超 [-180,180]、纬度超 [-90,90] INVALID LONGITUDE_OUT_OF_RANGE / LATITUDE_OUT_OF_RANGE false
true 且 (0,0) INVALID ZERO_COORDINATE false
true 且通过上述检查 VALID null true

全部结果固定标 crs=WGS84,验证器不转换坐标、不验证 CRS 来源、不检查当地合理范围。表依据:完整验证器:5–31。因此未验证的越界/缺坐标对象仍优先呈 UNVERIFIED;如果另需完整性诊断,应另设诊断事实,不能改 false 为 true 来取得 INVALID。通过范围检查的 (12,12) 或错误 CRS 值也不能据此获得业务可信性。

真实业务 map adapter 对监测点和设备都传 false,设备事实 resolver 对绑定设备也用相同验证器传 false;服务逐对象透传真实坐标并生成校验结论,而不是删除不可渲染对象。三类新增设施没有可信来源时应保持相同默认,线段则需要分别验证两端,任何一端未验证/无效均不能渲染整段。adapter 点位/设备:234–262、设备 resolver:75–81、地图点位校验:283–296、地图独立设备校验:339–351。

7. 未知行业如何保留

现有正式行业四个:GAS/WATER_SUPPLY/DRAINAGE/MANHOLE。设备类型树口径是根 1供水/2排水/3燃气/4窨井;沿 parentId 上溯,不将窨井并入排水。未知根、一般缺失中间节点或环返回 null。细节:实现遇到 parentId 恰为 1..4 会直接映射,并不再检查该根记录是否存在;严格“父级缺失全部拒绝”不能仅据注释认定已实现。行业树:13–62。

地图服务解析不出类型、类型 kind 不是 SMART_DEVICE、行业不在正式域时均输出 industry=null;默认不排除该对象。未设置 industry/deviceType 筛选时保留,指定正式行业时 null 不匹配;指定 deviceType 时必须字典可解析。请求 industry 的白名单只有四行业,UNKNOWN 不是已有合法请求值。行业入参:176–184、可空行业/过滤:214–245。

监测点处理保留有有效 pointCode 的空点、混合类型点与未验证坐标点;行业/类型不确定不是身份无效。适配器只在解析成功的设备类型集合大小=1时填 typeCode;一个未知设备类型不会进入该集合,因此“唯一可解析类型”不等于全部设备类型可信且唯一,后续若强化行业可信度应显式定义混合/缺字典规则。服务仍返回对象及坐标结论,统计的是点位对象与未关联设备对象,不是上图 marker 数。adapter:211–243、对象过滤/构造:248–296、总量/分页:101–127。

建议新设施读模型沿用 industry=null + 原始 networkType/pointType + 映射原因 保留未分类对象;以稳定的“对象种类+真实主键”建立身份,networkId 单独表达关联,不把未知值降到排水/燃气。窨井台账作为窨井对象种类可以与其关联管网行业分开表达,避免关联到供排水时将 MANHOLE 身份覆盖。以上为新契约建议;既有 map adapter 还没有设施 SourceType 或这些字段。

8. 漏洞与边界建议(静态发现,未修改实现)

  1. 可信状态伪造风险,最高优先级。 既有 GIS Feature、geoCompleteCount、字段 WGS84 标注、bdLon/bdLat 名称均不提供核验链。设施新读模型默认 UNVERIFIED;接入可信来源时记录来源标识、核验时间/人或流程、CRS、坐标版本,坐标变更后旧校核失效;不要接受前端自报 true。验证器的 boolean 输入与真实 adapter false 的事实见第 6 节。
  2. 字典混用与旧资料误导。 显式维护三套映射;MonitorPoint.pointType 不冒充 equipment_type 叶子 ID,networkType 不套 1/2/3行业枚举;GasPipePoint.pointType 在真实存储字典确认前保留 raw 值。修正“点位无类型列”的旧注释/说明属于后续任务,本次只记录冲突。依据见第 3 节。
  3. 关系悬空与错误行业继承。 networkId 应使用统一设施主键查正常管网;查不到时保留设施原始关系与 UNKNOWN/关联缺失,不借 networkName、编码前缀或最近线段补造。三种服务缺反向引用检查的事实见第 2 节;不要把按 networkId 查到管点就当作管网仍有效的证明。
  4. 已知查询范围缺口。 通用 GIS equipments 忽略 equipmentTypeId;供水 pipe detail 未约束 networkType;供水 features 只识别标准 '2',通用 GIS 接受历史别名;窨井 GeoJSON 缺 networkId。后续需统一筛选口径并通过完整台账保留关系,不能直接拼接各 GIS 输出声称范围一致。依据见第 5 节。
  5. 缺坐标对象被几何输出静默丢弃。 既有 GIS 使用判空后 continue/SQL IS NOT NULL,不能作为完整设施统计清单;新读模型应保留原始实体与校验理由,renderable 单独控制绘制。下拉 options 同样不是全字段来源。依据见第 4、5、6 节。另须明确分页/快照边界:现有业务 map adapter 签发后固定并缓存自身监测点/设备快照;分别调用现有 GIS/设施列表不会自动加入该版本,新几何接口不能仅回显同一 snapshotAt 就声称内容来自同一读取快照。快照签发/缓存:105–172、当前快照组成:198–274。
  6. 线段与坐标系统边界。 两端点字段只能表达直线;不能补造折线、中间节点、贴地形轨迹或真实连接拓扑。新读取路径逐端检验、整段聚合;考虑同点退化线、零端点、越界及 CRS 证据缺失。现验证器没有当地范围/退化线规则;新增规则必须作为新契约审定,不应冒充已有校验行为。依据见第 2、6 节。
  7. 对象身份与删除边界。 PointId Long 与监测点 String ID、窨井 UUID 须加对象种类命名空间,关联表按自身删除策略处理;status=2 不能当 delFlag=2。直接 SQL 对每张可逻辑删除表显式限制正常值。独立排水模型不能继承本次统一设施字段/删除/CRS假设。依据见第 2、4、5 节。
  8. 暴露面需单独复核。 通用 GIS 读接口带 @Anonymous,燃气管点与窨井的关联新增/批量新增/删除也带 @Anonymous 且直接调用 mapper;源码可见缺少该方法级权限检查与关系存在性校验,但不能在未读取全部安全配置/数据库约束、未做请求验证时宣布实际可匿名越权。本次只建议独立安全复核,不执行调用。通用 GIS:35–37、113–115、141–143、管点关系写入:151–176、窨井关系写入:101–126。

后续需要另行授权的验证项:实际部署 monitor_point.point_type 是否存在及现网值;燃气管点真实字典;三类设施坐标 CRS 与可信校核来源;networkId 外键/悬空/跨行业情况;逻辑删除实际 SQL。当前研究已给出可用源码依据,但没有执行这些运行时验证。