geoserver rest方式发布shp

admingeoserver rest方式发布shp已关闭评论条评论 408 次浏览

geoserver rest方式发布shp服务

工作需求,要在Web端提供发布shp服务的功能,并且能够使用户对shp图层的样式进行编辑。样式编辑属于后话了,现在还没到达这一步,只是把shp服务发布做完了(样式采用默认的)

基本访问方法

我们知道使用rest方式访问geoserver,很多功能都需要认证(Authorization)信息,否则是获取不到实际数据的。所以我们需要在请求头里面加上Authorization,使得客户端具有访问的权限。

如果是用jquery/webpack-zepto的话,那么就

const fetchList = () => {
  let results = null
  $.ajax({
    url: 'geoserver/rest/layers.json',
    dataType: 'json',
    type: 'GET',
    async: false,
    success: (result) => {
      results = result.layers.layer
    },
    headers: {
      'Authorization': 'Basic YWRtaW46Z2Vvc2VydmVy'
    }
  })
  return results
}
注意ajax参数中的url,因为我用nginx做了代理,使得访问不像是跨域。由于在headers中加入了认证信息,浏览器会先options方式请求,这样就导致第一次请求的失败,因为geoserver并没有为options请求方式提供对应的接口,它会提示403,就是说它理解了这次请求并拒绝了你,感觉就像是女孩说的话。

至于这个认证信息,就是BASE64对geoserver用户名密码的编码。我的是admin:geoserver,注意这个格式,然后去base64加密,如果账号信息没有修改过,跟我的一样,YWRtaW46Z2Vvc2VydmVy就直接拿去用吧

为了方便,我把nginx配置文件也亮出来吧
    server {
        listen       8040;
        server_name  localhost;

        location /geoserver/ {
            proxy_pass http://localhost:8080;
            proxy_redirect  off;
        }

        location / {
            proxy_pass http://localhost:8030;
            proxy_redirect  off;
        }
    }

其中8040是系统应用的端口,将来向外网映射时也会用这一个。

当访问localhost:8040/geoserver/时,就会转发至geoserver服务地址,其余都会转发至我的nodejs服务器。

SHP发布

言归正传,前面只是举例说明一下访问geoserver的一些基本操作,下面进行shp发布
    // 发布
    $('#new_pubtn').on('click', function () {
      // validate data integrity
      // ...
      let file = $('#new_file')[0].files[0]
      let option = {
        workspace: $('#new_workspace').val(),
        datastore: $('#new_datastore').val(),
        type: $('#new_type').val(),
        file: file,
        name: file.name.substring(0, file.name.indexOf('.'))
      }

      utils.publish(option)
    })

这段代码很简单,通过字面意思就很容易明白各项所代表的含义了,就不再展示html怎么写了。总之这几项是我发布shp的几个必须字段(除了那个type吧。。。)

下面看看发布方法

const publish = (option) => {
  let results = null
  if (option.type === 'VECTOR') {
    let formData = new window.FormData()
    formData.append('file', option.file)
    $.ajax({
      url: 'geoserver/rest/workspaces/' + option.workspace + '/datastores/' + option.datastore + '/file.shp?charset=GB2312',
      type: 'PUT',
      async: false,
      data: formData,
      contentType: false,
      processData: false,
      headers: {
        'Authorization': 'Basic YWRtaW46Z2Vvc2VydmVy',
        'Content-type': 'application/zip'
      },
      success: (data, textStatus, jqXHR) => {
        if (jqXHR.status === 201) {
          fixPublish(option)
        }
      }
    })
  }
  return results
}

我发现如果不再url后面追加charset=GB2312这种编码格式,服务中的字段值都是一些乱码,至少我发布的几个服务都是出现了乱码(有中文的)。

上传的shapefile必须要先打包成zip,这是官网说的,只能照做。注意打包时shapefile不能包含在文件夹中,就是说把shapefile的一系列文件选中后右键“添加到压缩文件…”而不是把shapefile放到文件夹中再压缩。
当服务器返回201时,就表示创建成功了。

fix bug

官网说就好了,表示“Uploads files to the data store ds, creating it if necessary”,这个“if necessary”是什么鬼?查看geoserver发现datastore确实已经创建了,但是打不开。。。 
而且这个图层也没有发布,预览也是不可能的。

工作中一直用的是CGCS2000坐标系,而geoserver默认的是4326,所以如果不是WGS84坐标系的话,就需要这个“fix bug”

当我在geoserver中为发布失败的图层进行手动发布时,才发现shp之所以没有发布时因为没有定义srs,为什么。。。翻出几个月前自己写的也是shp发布的代码,原来配置文件也要修改,一刹那感觉自己以前这么厉害,简直大神啊。

<featureType>
  <srs>EPSG:4490</srs>
  <projectionPolicy>FORCE_DECLARED</projectionPolicy>
  <enabled>true</enabled>
</featureType>

这几行代码是我很久之前通过比较两者(手动shp发布和代码提交发布)配置文件featuretype.xml是发现的于是

const fixPublish = (option, index = 0) => {
  let results = null
  let content = null
  let url = null
  if (option.type === 'VECTOR') {
    url = 'geoserver/rest/workspaces/' + option.workspace + '/datastores/' + option.datastore + '/featuretypes/' + option.name + (index === 0 ? '' : index)
    content = '<featureType><srs>EPSG:4490</srs><projectionPolicy>FORCE_DECLARED</projectionPolicy> <enabled>true</enabled></featureType>'
  }
  $.ajax({
    url: url,
    type: 'PUT',
    async: false,
    data: content,
    headers: {
      'Authorization': 'Basic YWRtaW46Z2Vvc2VydmVy',
      'Content-type': 'text/xml'
    },
    success: (data, textStatus, jqXHR) => {
      if (jqXHR.status === 200) {
        results = '发布成功!'
      }
    },
    error: (jqXHR, textStatus, errorThrown) => {
      if (jqXHR.status === 404) {
        index++
        // 当超过10次时,放弃
        if (index <= 10) {
          fixPublish(option, index)
        }
      }
    }
  })
  return results
}

至于这个index,当我们对一个shp提交多次以后,哪怕datastore不同,shp后面中是会添加相应的数字以区分之前提交shp,比如我提交data.zip,里面压缩的是dahong.shp,第一次图层的名称是dahong,第二次提交就是dahong1,第三次dahong2… 
因为名称和datastore不同,又无法获知你提交过相同的shp多少次,所以就这么写了,确实有点儿心机boy的感觉