一、项目背景
在GIS项目中,我们经常需要将Shapefile数据发布为地图服务。传统方式需要手动登录iServer管理界面,创建Provider和Component,操作繁琐且容易出错。
本文介绍如何使用Python实现监听指定目录,当检测到新的SHP目录时自动注册到SuperMap iServer的自动化工具。
二、功能特性
| 功能 | 说明 |
|---|---|
| 📂 目录监听 | 使用watchdog库实时监控目录变化 |
| 📄 智能检测 | 自动检测目录是否包含SHP文件,避免误注册 |
| ⏱️ 上传等待 | 等待文件上传完成(静默N秒)后再注册 |
| 📊 状态记录 | JSON格式注册表,记录检索时间、发布时间、状态 |
| 🔄 启动扫描 | 服务启动时自动扫描已有目录并注册 |
| 🖥️ 窗口控制 | 支持前台显示窗口/后台无窗口运行 |
| 🚀 开机自启 | 支持注册为Windows开机自启服务 |
| 📦 一键打包 | 提供PowerShell脚本打包为exe可执行文件 |
三、技术栈
- Python 3.8+:主开发语言
- watchdog:文件系统监听库
- requests:HTTP请求库(调用iServer REST API)
- PyInstaller:打包工具
- SuperMap iServer REST API:服务注册接口
四、核心实现
4.1 目录监听
使用watchdog库监听目录创建事件:
python
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class ShpDirectoryHandler(FileSystemEventHandler):
def on_created(self, event):
if not event.is_directory:
return
dir_path = event.src_path
if os.path.isdir(dir_path):
time.sleep(1) # 防止重复触发
register_directory(dir_path)
# 启动监听器
observer = Observer()
observer.schedule(event_handler, watch_dir, recursive=False)
observer.start()
4.2 SHP文件检测
注册前检查目录是否包含.shp文件:
python
def has_shp_files(dir_path):
"""检查目录是否包含shp文件"""
for root, dirs, files in os.walk(dir_path):
for file in files:
if file.lower().endswith('.shp'):
return True
return False
4.3 等待文件上传完成
实现静默等待机制,确保文件上传完成:
python
def wait_for_stable(dir_path, stable_sec, max_wait_sec):
"""等待目录文件上传完成"""
elapsed = 0
last_modify_time = 0
while elapsed < max_wait_sec:
current_max_modify = 0
for root, dirs, files in os.walk(dir_path):
for file in files:
mtime = os.path.getmtime(os.path.join(root, file))
if mtime > current_max_modify:
current_max_modify = mtime
if current_max_modify == last_modify_time:
# 静默期内无文件修改,认为上传完成
return True
last_modify_time = current_max_modify
elapsed += stable_sec
time.sleep(stable_sec)
return True # 超时强制继续
4.4 iServer服务注册
调用iServer REST API注册Provider和Component:
python
def register_provider(dir_path):
"""注册Provider"""
provider_name = f"shapefileMap-{os.path.basename(dir_path)}"
url = f"{iserver_host}/iserver/manager/providers.json?token={token}"
payload = {
"config": {
"shpDir": dir_path,
"charset": "GBK",
"stylePath": "",
"cacheEnabled": False
},
"name": provider_name,
"type": "com.supermap.services.providers.ShapeFileMapProvider"
}
response = requests.post(url, json=payload)
return provider_name if response.status_code in range(200, 300) else None
def register_component(provider_name, dir_path):
"""注册Component"""
component_name = f"map-shapefile-{os.path.basename(dir_path)}"
url = f"{iserver_host}/iserver/manager/components.json?token={token}"
payload = {
"interfaceNames": "rest",
"name": component_name,
"providers": provider_name,
"config": {
"outputPath": "",
"outputSite": "",
"logLevel": "info"
},
"type": "com.supermap.services.components.impl.MapImpl"
}
response = requests.post(url, json=payload)
return component_name if response.status_code in range(200, 300) else None
4.5 注册状态记录
使用JSON文件记录每个目录的注册状态:
python
def update_registry(dir_path, status, retrieve_time=None, publish_time=None, error_msg=None):
"""更新注册表记录"""
registry = load_registry()
record = registry.get(dir_path, {})
if retrieve_time:
record['retrieve_time'] = retrieve_time
if publish_time:
record['publish_time'] = publish_time
record['status'] = status
record['dir_path'] = dir_path
record['dir_name'] = os.path.basename(dir_path)
if error_msg:
record['error_message'] = error_msg
registry[dir_path] = record
save_registry(registry)
注册表示例(registry.json):
json
{
"D:\\data\\shp\\cities": {
"retrieve_time": "2026-07-24T10:00:00.000000",
"publish_time": "2026-07-24T10:00:15.000000",
"status": "success",
"dir_path": "D:\\data\\shp\\cities",
"dir_name": "cities"
}
}
状态说明:
pending:目录已检测到,等待注册skipped:目录不包含SHP文件,跳过success:注册成功failed:注册失败
五、项目结构
shp_watcher/
├── watch_shp.py # 主程序
├── config.ini # 配置文件
├── build.ps1 # 打包脚本
├── startup.bat # 前台启动脚本
├── startup_background.bat # 后台启动脚本
└── dist/ # 打包输出目录
├── shp_watcher.exe # 可执行文件
├── config.ini # 配置文件
└── registry.json # 注册表(自动生成)
六、配置文件说明
config.ini配置项:
ini
[iServer]
host = http://172.16.12.27:8090 # iServer服务地址
token = your_token_here # 管理Token
charset = GBK # SHP字符集
style_path = # 样式文件路径(可选)
cache_enabled = false # 是否启用缓存
[Watcher]
watch_dir = D:\data\shp # 监听目录(必须绝对路径!)
stable_seconds = 5 # 静默判定时间(秒)
max_wait_seconds = 300 # 最大等待时间(秒)
[System]
background = false # 是否后台运行
auto_start = false # 是否开机自启
⚠️ 注意 :
watch_dir必须设置为绝对路径!
七、使用方法
7.1 获取iServer Token
登录iServer管理界面 → 令牌 → 生成Token
7.2 运行方式
bash
# 方式1:直接运行exe(前台模式,显示窗口)
shp_watcher.exe
# 方式2:前台模式(通过bat脚本)
startup.bat
# 方式3:后台模式(无窗口)
startup_background.bat
shp_watcher.exe --background
# 方式4:安装开机自启
shp_watcher.exe --install
# 方式5:卸载开机自启
shp_watcher.exe --uninstall
7.3 打包为exe
powershell
powershell -ExecutionPolicy Bypass -File build.ps1
打包脚本会自动:
- 检查Python环境
- 安装依赖包(watchdog, requests, pyinstaller)
- 执行PyInstaller打包
- 复制配置文件和启动脚本
八、运行流程
启动服务
│
├── 加载配置文件
├── 加载注册表记录
├── 扫描已有目录
│ │
│ ├── 包含SHP文件?
│ │ ├── 是 → 更新检索时间 → 等待稳定 → 注册Provider → 注册Component → 更新状态
│ │ └── 否 → 跳过
│ │
└── 启动目录监听器
│
├── 检测到新目录创建
│ │
│ ├── 包含SHP文件?
│ │ ├── 是 → 更新检索时间 → 等待稳定 → 注册Provider → 注册Component → 更新状态
│ │ └── 否 → 跳过
│ │
└── 持续监听...
九、注意事项
- 监听目录必须是绝对路径 :如
D:\data\shp或/mnt/data/shp - iServer Token有效期:建议设置较长有效期或定期更新
- 开机自启需要管理员权限:首次安装时会自动提升权限
- 日志文件 :默认生成在exe同级目录的
iserver_register.log - 注册表文件 :默认生成在exe同级目录的
registry.json - 后台运行 :可通过
--background参数或startup_background.bat实现
十、总结
本工具实现了从SHP目录检测到iServer服务注册的全流程自动化,主要优势:
- 节省人力:无需手动登录iServer管理界面
- 及时响应:新目录创建后自动触发注册
- 避免错误:智能检测SHP文件,避免误注册
- 状态追踪:注册表记录便于追溯和排查问题
- 灵活部署:支持前台/后台运行,支持开机自启
- 跨平台兼容:核心逻辑可移植到Linux环境
完整代码 :GitHub仓库
如果觉得本文对你有帮助,欢迎点赞、收藏、评论!如有问题,欢迎留言讨论。