基于geoserver开发地图发布服务 您所在的位置:网站首页 urlparse安装不了 基于geoserver开发地图发布服务

基于geoserver开发地图发布服务

2023-06-13 11:41| 来源: 网络整理| 查看: 265

写在前面:我在github上创建了对应的项目,可点此跳转,本文的所有源码均可在项目里找到,欢迎大家访问交流

一、开发背景

在gis领域,geoserver是后端地图发布的开源项目。目前我们在启动服务后,可通过自带的web应用进行地图发布操作,这个过程是简单有效的,但是,如果我们想要把地图发布的功能集成到自己的平台里,仍旧使用geoserver的web应用就显得格格不入,为此我们需要对geoserver的功能进行封装,开发自己的后端服务,并配套对应的前端功能(自带的web应用只将其当作管理工具)。本篇研究了基于python语言开发的geoserver-restconfig库,该库封装了geoserver的常用操作函数,考虑到自身的需求以及该库存在的问题,本篇在该库的基础上开发了新的服务类,主要用于发布shp、普通tiff、大型tiff,经过测试,该服务类可正常使用,可用于后端服务的构建

二、geoserver-restconfig

基于python语言开发的geoserver使用库,安装: pip install geoserver-restconfig

可进行工作区的创建删除、shp图层的创建删除、tiff图层的创建删除等。但是在使用时存在两个问题: 1、类实例化失败(requests版本为2.30):TypeError: Retry.__init__() got an unexpected keyword argument 'method_whitelist' 2、该库不支持切片tiff的发布

三、GeoServerCatalog

针对上述问题,对该库的核心类Catalog进行派生,主要做两个改动

3.1 重构create_coveragestore函数

该函数可用于栅格数据的发布,其中GeoTIFF类型就是tiff文件发布对应的类型,在我的另一篇文章:使用geoserver发布shp和tiff数据 中已经介绍了使用geoserver发布切片tiff目录的方法,对应的类型是ImagePyramid,但此类型在该类中没有(没有是正常的,因为切片tiff类型是通过插件方式增加的),所以我们重写该函数,在allowed_types中增加ImagePyramid即可,其他相同 在这里插入图片描述

3.2 重构setup_connection函数

经调试发现,Retry 的报错是由于对象实例化时参数不对,主要是method_whitelist 这个变量名不对,经过排查,确认是requests库的版本不对,2.30版本的Retry类用的是allowed_methods,2.28版本用的是method_whitelist,为了兼容不同的版本,在派生类中重写该函数,通过try except来捕获由于版本差异导致的异常,在捕获异常时,使用另一版本的参数

3.3 源码 # GeoServerCatalog.py import os from geoserver.catalog import Catalog, ConflictingDataError, _name, FailedRequestError from geoserver.store import UnsavedCoverageStore from geoserver.support import build_url import requests from requests.packages.urllib3.util.retry import Retry from requests.adapters import HTTPAdapter try: from urllib.parse import urlparse except ImportError: from urlparse import urlparse class GeoServerCatalog(Catalog): """ geoserver.Catalog的派生类 用于扩展基类的create_coveragestore函数,使其支持"ImagePyramid"类型 """ def __init__(self, service_url, username="admin", password="geoserver", validate_ssl_certificate=True, access_token=None, retries=3, backoff_factor=0.9): super().__init__(service_url, username, password, validate_ssl_certificate, access_token, retries, backoff_factor) def create_coveragestore(self, name, workspace=None, path=None, type='GeoTIFF', create_layer=True, layer_name=None, source_name=None, upload_data=False, contet_type="image/tiff", overwrite=False): """ Create a coveragestore for locally hosted rasters. If create_layer is set to true, will create a coverage/layer. layer_name and source_name are only used if create_layer ia enabled. If not specified, the raster name will be used for both. """ if path is None: raise Exception('You must provide a full path to the raster') if layer_name is not None and ":" in layer_name: ws_name, layer_name = layer_name.split(':') allowed_types = [ 'ImageMosaic', 'GeoTIFF', 'Gtopo30', 'WorldImage', 'AIG', 'ArcGrid', 'DTED', 'EHdr', 'ERDASImg', 'ENVIHdr', 'GeoPackage (mosaic)', 'NITF', 'RPFTOC', 'RST', 'VRT', 'ImagePyramid' ] if type is None: raise Exception('Type must be declared') elif type not in allowed_types: raise Exception(f"Type must be one of {', '.join(allowed_types)}") if workspace is None: workspace = self.get_default_workspace() workspace = _name(workspace) if not overwrite: stores = self.get_stores(names=name, workspaces=[workspace]) if len(stores) > 0: msg = f"There is already a store named {name} in workspace {workspace}" raise ConflictingDataError(msg) if upload_data is False: cs = UnsavedCoverageStore(self, name, workspace) cs.type = type cs.url = path if path.startswith("file:") else f"file:{path}" self.save(cs) if create_layer: if layer_name is None: layer_name = os.path.splitext(os.path.basename(path))[0] if source_name is None: source_name = os.path.splitext(os.path.basename(path))[0] data = f"{layer_name}{source_name}" url = f"{self.service_url}/workspaces/{workspace}/coveragestores/{name}/coverages.xml" headers = {"Content-type": "application/xml"} resp = self.http_request(url, method='post', data=data, headers=headers) if resp.status_code != 201: raise FailedRequestError('Failed to create coverage/layer {} for : {}, {}'.format(layer_name, name, resp.status_code, resp.text)) self._cache.clear() return self.get_resources(names=layer_name, workspaces=[workspace])[0] else: data = open(path, 'rb') params = {"configure": "first", "coverageName": name} url = build_url( self.service_url, [ "workspaces", workspace, "coveragestores", name, f"file.{type.lower()}" ], params ) headers = {"Content-type": contet_type} resp = self.http_request(url, method='put', data=data, headers=headers) if hasattr(data, "close"): data.close() if resp.status_code != 201: raise FailedRequestError('Failed to create coverage/layer {} for : {}, {}'.format(layer_name, name, resp.status_code, resp.text)) return self.get_stores(names=name, workspaces=[workspace])[0] def setup_connection(self, retries=3, backoff_factor=0.9): self.client = requests.session() self.client.verify = self.validate_ssl_certificate parsed_url = urlparse(self.service_url) try: retry = Retry( total = retries or self.retries, status = retries or self.retries, read = retries or self.retries, connect = retries or self.retries, backoff_factor = backoff_factor or self.backoff_factor, status_forcelist = [502, 503, 504], allowed_methods = set(['HEAD', 'TRACE', 'GET', 'PUT', 'POST', 'OPTIONS', 'DELETE']) ) # allowed_methods : requests > 2.30.0 except TypeError: retry = Retry( total = retries or self.retries, status = retries or self.retries, read = retries or self.retries, connect = retries or self.retries, backoff_factor = backoff_factor or self.backoff_factor, status_forcelist = [502, 503, 504], method_whitelist = set(['HEAD', 'TRACE', 'GET', 'PUT', 'POST', 'OPTIONS', 'DELETE']) ) # method_whitelist : requests


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有