地区与 IP
地区与 IP 能力为后台页面、日志审计、表单字段和用户画像提供统一的地理信息基础。RuoYi Office 后端在启动时把 area.csv 和 ip2region.xdb 加载到内存中,管理端“地区列表”页面展示中国地区树,并提供 IP 地址归属地查询。
本地实现位置
| 层 | 位置 |
|---|---|
| PC 页面 | ruoyi-office-vben/apps/web-antd/src/views/system/area |
| PC API | ruoyi-office-vben/apps/web-antd/src/api/system/area |
| 后端 Controller | yudao-module-system-server/.../controller/admin/ip/AreaController.java |
| 地区工具 | yudao-spring-boot-starter-biz-ip/.../AreaUtils.java |
| IP 工具 | yudao-spring-boot-starter-biz-ip/.../IPUtils.java |
管理端能力
地区页面使用 VbenVxeGrid 展示树形数据,表格字段主要包括地区编码和地区名称。工具栏提供“IP 查询”,输入合法 IP 后调用后端接口返回格式化地区名称。
| 功能 | 接口 | 说明 |
|---|---|---|
| 地区树 | GET /system/area/tree | 返回中国节点下的省、市、区树 |
| IP 归属地 | GET /system/area/get-by-ip?ip=... | 返回格式化地区,无法匹配时返回 未知 |
数据加载方式
AreaUtils 会读取 area.csv,构造地区编号、名称、类型、父子关系,并把地区数据缓存在内存 Map 中。IPUtils 会读取 ip2region.xdb,创建查询器后按 IP 查询地区编号,再交给 AreaUtils.format 转成可读名称。
地区格式化
AreaUtils.format(id) 默认使用空格拼接地区路径,并且在中国地区下跳过“中国”父节点。
| 输入层级 | 示例输出 |
|---|---|
| 省级 | 北京市 |
| 市级 | 北京市 北京市 |
| 区县级 | 北京市 北京市 朝阳区 |
| 未匹配 | null 或接口层返回 未知 |
如果业务需要斜杠路径,可以使用 AreaUtils.format(id, "/")。如果需要从“省/市/区”文本反查地区对象,可以使用 AreaUtils.parseArea(pathStr)。
使用场景
| 场景 | 建议 |
|---|---|
| 表单地区字段 | 保存地区编号,展示时用 AreaUtils.format 或前端树数据翻译 |
| Excel 地区列 | 使用 Excel 地区转换器,避免手写字符串解析 |
| 登录/操作日志 | 记录原始 IP,展示时可结合 IP 查询能力补充地区 |
| 限流与风控 | 使用 ServletUtils.getClientIP() 获取客户端 IP,再结合地区或 IP 维度策略 |
二开建议
- 不要把地区数据当业务表维护:当前地区来源是静态资源和内存缓存,不是数据库表。
- 更新地区库要同步资源文件:如需调整行政区划,需要更新
area.csv;如需提高 IP 精度,需要更新ip2region.xdb。 - 反向代理要保留真实 IP:如果网关或 Nginx 没有正确传递客户端 IP,登录日志和 IP 查询会显示代理地址。
- 前端校验只做第一层保护:地区页的 IP 输入使用 zod IP 校验,后端仍应按工具类异常和未知结果处理。
排查清单
| 现象 | 排查方向 |
|---|---|
| 地区树为空 | 检查 area.csv 是否打包进后端资源、启动日志是否有 AreaUtils 加载失败 |
| IP 查询一直未知 | 检查 ip2region.xdb、IP 是否为内网地址或数据库未覆盖 |
| 登录日志 IP 不准确 | 检查反向代理、网关和 X-Forwarded-For 配置 |
| Excel 地区导入失败 | 检查地区路径分隔符和地区名称是否与 area.csv 一致 |
