318 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Markdown
		
	
	
	
			
		
		
	
	
			318 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Markdown
		
	
	
	
---
 | 
						||
title: GeoServer二次开发-WPS服务
 | 
						||
date: 2021-04-26
 | 
						||
author: ac
 | 
						||
tags: 
 | 
						||
 - GeoServer
 | 
						||
categories:
 | 
						||
 - GIS
 | 
						||
---
 | 
						||
 | 
						||
> 本文内容主要来源于GeoServer官网二次开发的WPS Serveice篇,以及在本地实操的示例。
 | 
						||
 | 
						||
<!-- more -->
 | 
						||
 | 
						||
## 1. WPS 规范1.0.0
 | 
						||
 | 
						||
[WPS规范](http://www.opengeospatial.org/standards/wps)
 | 
						||
 | 
						||
## 2.基础结构
 | 
						||
 | 
						||
该模块基于通常的`GeoServer OWS`框架应用程序:
 | 
						||
 | 
						||
- `KVP`解析器和`KVP`读取器,用于解析HTTP GET请求的(可以在`org.geoserver.wps.kvp`包中找到);
 | 
						||
- `XML`解析器,用于解析HTTP POST请求的(可在`org.geoserver.wps.xml`和`org.geoserver.wps.xml.v1_0_0`中找到)
 | 
						||
- 一个响应各种`WPS`方法的服务对象接口和实现,特别是`org.geoserver.wps.DefaultWebProcessingService`,它依次将大部分工作委托给`GetCapabilities`、`DescribeProcess`和`ExecuteProcess`类
 | 
						||
- 输出转换器,将通过`DefaultWebProcessingService`生成的结果转换为适当的响应(通常是XML),可以在`org.geoserver.wps.response`包中找到其中的一些,而另一些是在Spring上下文中已参数化并声明的通用类(请参见`applicationContext.xml`文件)
 | 
						||
 | 
						||
该模块常用的`GeoTools`包有:
 | 
						||
 | 
						||
- `net.opengis.wps`,它包含`WPS`模式中描述的各种元素和类型的EMF模型。这些对象通常是在KVP解析器、XML解码器、服务实现和输出转换器之间流动的对象。
 | 
						||
- `gt-xsd-wps` and `gt-xsd`,用于XML编码和解码。
 | 
						||
- `gt-process`,它提供了`process`的概念,能够自我描述其输入和输出,当然还能够执行和产生结果。
 | 
						||
 | 
						||
 | 
						||
 | 
						||
## 3. Process
 | 
						||
 | 
						||
该模块依赖于gt-process基于SPI的插件机制来查找和使用类路径中可用的进程。实现一个新process可以归结为以下步骤:
 | 
						||
 | 
						||
1. 创建一个`ProcessFactory`的实现;
 | 
						||
2. 创建一个或多个 `Process` 的实现;
 | 
						||
3. 通过添加工厂类名到`META-INF/services/org.geotools.processProcessFactory`文件中,实现在`SPI`中注册`ProcessFactory`。
 | 
						||
 | 
						||
## 4.WPS示例
 | 
						||
 | 
						||
按照之前的[环境搭建](./devEnvironment.md)的操作已经将 GeoServer的扩展插件部分`extension`也打包到了本地的Maven仓库中了。
 | 
						||
 | 
						||
现在我们开始来实现一个简单的OWS服务。
 | 
						||
 | 
						||
1. 新建一个Maven项目
 | 
						||
2. 创建process类
 | 
						||
3. 在GeoServer中注册process
 | 
						||
4. 打包编译
 | 
						||
5. 测试
 | 
						||
 | 
						||
### 新建一个Maven项目
 | 
						||
 | 
						||

 | 
						||
 | 
						||
将项目中的Maven指定为本地的安装路径,这样就可以引用之前源码打包的各模块的jar。
 | 
						||
 | 
						||

 | 
						||
 | 
						||
在pom.xml文件中添加依赖以及指定打包方式,需要注意gt和gs的版本问题,版本可以在之前部署的GeoServer源码根目录下的pom.xml文件中找到:
 | 
						||
 | 
						||
```xml
 | 
						||
<?xml version="1.0" encoding="UTF-8"?>
 | 
						||
<project xmlns="http://maven.apache.org/POM/4.0.0"
 | 
						||
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
						||
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
						||
    <modelVersion>4.0.0</modelVersion>
 | 
						||
 | 
						||
    <groupId>org.geoserver</groupId>
 | 
						||
    <artifactId>hello_wps</artifactId>
 | 
						||
    <version>1.0-SNAPSHOT</version>
 | 
						||
 | 
						||
    <packaging>jar</packaging>
 | 
						||
    <name>hello_wps</name>
 | 
						||
 | 
						||
    <properties>
 | 
						||
        <maven.compiler.source>8</maven.compiler.source>
 | 
						||
        <maven.compiler.target>8</maven.compiler.target>
 | 
						||
        <gs.version>2.20-SNAPSHOT</gs.version>
 | 
						||
        <gt.version>26-SNAPSHOT</gt.version>
 | 
						||
        <local.project.version>2.18.2</local.project.version>
 | 
						||
    </properties>
 | 
						||
 | 
						||
    <dependencies>
 | 
						||
        <dependency>
 | 
						||
            <groupId>org.geotools</groupId>
 | 
						||
            <artifactId>gt-process</artifactId>
 | 
						||
            <version>${gt.version}</version>
 | 
						||
        </dependency>
 | 
						||
        <dependency>
 | 
						||
            <groupId>org.geoserver.extension</groupId>
 | 
						||
            <artifactId>gs-wps-core</artifactId>
 | 
						||
            <version>${gs.version}</version>
 | 
						||
        </dependency>
 | 
						||
        <dependency>
 | 
						||
            <groupId>org.geoserver</groupId>
 | 
						||
            <artifactId>gs-main</artifactId>
 | 
						||
            <version>${gs.version}</version>
 | 
						||
            <classifier>tests</classifier>
 | 
						||
            <scope>test</scope>
 | 
						||
        </dependency>
 | 
						||
        <dependency>
 | 
						||
            <groupId>junit</groupId>
 | 
						||
            <artifactId>junit</artifactId>
 | 
						||
            <version>4.11</version>
 | 
						||
            <scope>test</scope>
 | 
						||
        </dependency>
 | 
						||
        <dependency>
 | 
						||
            <groupId>com.mockrunner</groupId>
 | 
						||
            <artifactId>mockrunner</artifactId>
 | 
						||
            <version>0.3.6</version>
 | 
						||
            <scope>test</scope>
 | 
						||
        </dependency>
 | 
						||
    </dependencies>
 | 
						||
 | 
						||
    <repositories>
 | 
						||
        <repository>
 | 
						||
            <releases>
 | 
						||
                <enabled>true</enabled>
 | 
						||
            </releases>
 | 
						||
            <!-- contains release (including third-party-dependences)               -->
 | 
						||
            <!-- Restlet maven Repository (http://maven.restlet.org)                             -->
 | 
						||
            <!-- ucar (https://artifacts.unidata.ucar.edu/content/repositories/unidata-releases) -->
 | 
						||
            <snapshots>
 | 
						||
                <enabled>false</enabled>
 | 
						||
            </snapshots>
 | 
						||
            <id>osgeo-releases</id>
 | 
						||
            <name>OSGeo Nexus Release Repository</name>
 | 
						||
            <url>https://repo.osgeo.org/repository/release/</url>
 | 
						||
        </repository>
 | 
						||
 | 
						||
        <repository>
 | 
						||
            <releases>
 | 
						||
                <enabled>false</enabled>
 | 
						||
            </releases>
 | 
						||
            <!-- contains snapshots               -->
 | 
						||
            <snapshots>
 | 
						||
                <enabled>true</enabled>
 | 
						||
            </snapshots>
 | 
						||
            <id>osgeo-snapshots</id>
 | 
						||
            <name>OSGeo Nexus Snapshot Repository</name>
 | 
						||
            <url>https://repo.osgeo.org/repository/snapshot/</url>
 | 
						||
        </repository>
 | 
						||
 | 
						||
        <repository>
 | 
						||
            <releases>
 | 
						||
                <enabled>true</enabled>
 | 
						||
            </releases>
 | 
						||
            <snapshots>
 | 
						||
                <enabled>true</enabled>
 | 
						||
            </snapshots>
 | 
						||
            <id>geosolutions</id>
 | 
						||
            <name>geosolutions repository</name>
 | 
						||
            <url>https://maven.geo-solutions.it/</url>
 | 
						||
        </repository>
 | 
						||
    </repositories>
 | 
						||
</project>
 | 
						||
```
 | 
						||
 | 
						||
 | 
						||
 | 
						||
### 创建process类
 | 
						||
 | 
						||
```java
 | 
						||
import org.geotools.process.factory.DescribeParameter;
 | 
						||
import org.geotools.process.factory.DescribeProcess;
 | 
						||
import org.geotools.process.factory.DescribeResult;
 | 
						||
import org.geoserver.wps.gs.GeoServerProcess;
 | 
						||
 | 
						||
@DescribeProcess(title="helloWPS", description="Hello WPS Sample")
 | 
						||
public class HelloWPS implements GeoServerProcess {
 | 
						||
 | 
						||
   @DescribeResult(name="result", description="output result")
 | 
						||
   public String execute(@DescribeParameter(name="name", description="name to return") String name) {
 | 
						||
 | 
						||
       return "Hello, " + name;
 | 
						||
   }
 | 
						||
}
 | 
						||
```
 | 
						||
 | 
						||
 | 
						||
 | 
						||
### 在GeoServer中注册process
 | 
						||
 | 
						||
在resource目录中创建`applicationContext.xml`文件,将刚创建的process类配置到GeoServer的Spring容器中:
 | 
						||
 | 
						||
```xml
 | 
						||
<?xml version="1.0" encoding="UTF-8"?>
 | 
						||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 | 
						||
<beans>
 | 
						||
    <bean id="helloWPS" class="org.geoserver.hello.wps.HelloWPS"/>
 | 
						||
</beans>
 | 
						||
```
 | 
						||
 | 
						||
 | 
						||
 | 
						||
### 打包编译
 | 
						||
 | 
						||
项目目录结构:
 | 
						||
 | 
						||
```yaml
 | 
						||
hello_wps/
 | 
						||
 + pom.xml
 | 
						||
  + src/
 | 
						||
    + main/
 | 
						||
      + java/
 | 
						||
      + resources/
 | 
						||
```
 | 
						||
 | 
						||
在项目根目录下使用maven命令打包项目:
 | 
						||
 | 
						||
```perl
 | 
						||
mvn clean install
 | 
						||
```
 | 
						||
 | 
						||
<img src="./images/image-20210429145215.png" alt="image-20210429145215386" style="zoom:50%;" />
 | 
						||
 | 
						||
将打包好的`hello_wps-1.0-SNAPSHOT.jar`拷贝到GeoServer的`/WEB-INF/lib`中,启动或重启GeoServer。
 | 
						||
 | 
						||
> 如果你部署在免安装的二进制或其他安装程序的GeoServer,请确保已添加对WPS服务的扩展。
 | 
						||
 | 
						||

 | 
						||
 | 
						||
添加扩展模块也很简单,直接将下载下来的zip里面的jar拷贝到`/WEB-INF/lib`中即可。
 | 
						||
 | 
						||
 | 
						||
 | 
						||
### 测试
 | 
						||
 | 
						||
启动GeoServer,在`演示`中找到`WPS request builder`进行测试:
 | 
						||
 | 
						||
<img src="./images/image-50504324.png" alt="image-20210429150504324" style="zoom: 50%;" />
 | 
						||
 | 
						||

 | 
						||
 | 
						||
 | 
						||
 | 
						||
`http://localhost:8080/geoserver/ows?service=wps&request=execute&version=1.0.0&Identifier=gs:HelloWPS&DataInputs=name="world"&RawDataOutput=result`
 | 
						||
 | 
						||

 | 
						||
 | 
						||
 | 
						||
 | 
						||
### 接收和返回原始数据
 | 
						||
 | 
						||
基本的GeoServer WPS体系结构旨在卸载和集中输入解码和输出编码,让进程针对Java对象工作,并在注册新的匹配PPIO后立即为所有进程自动创建新的输入和输出类型。
 | 
						||
 | 
						||
不过,也可以让流程同时接受原始输入和输出,并自行进行解析编码。
 | 
						||
 | 
						||
原始输入和输出由RawData接口表示:
 | 
						||
 | 
						||
```java
 | 
						||
public interface RawData {
 | 
						||
 | 
						||
    /**
 | 
						||
     * Returns the mime type of the stream's contents
 | 
						||
     *
 | 
						||
     * @return
 | 
						||
     */
 | 
						||
    public String getMimeType();
 | 
						||
 | 
						||
    /**
 | 
						||
     * Gives access to the raw data contents.
 | 
						||
     *
 | 
						||
     * @return
 | 
						||
     * @throws FileNotFoundException
 | 
						||
     */
 | 
						||
    public InputStream getInputStream() throws IOException;
 | 
						||
 | 
						||
    /**
 | 
						||
     * Optional field for output raw data, used by
 | 
						||
     * WPS to generate a file extension
 | 
						||
     *
 | 
						||
     * @return
 | 
						||
     */
 | 
						||
    public String getFileExtension();
 | 
						||
}
 | 
						||
```
 | 
						||
 | 
						||

 | 
						||
 | 
						||
 | 
						||
 | 
						||
作为一个输入,RawData将被提供给Process流程,该流程将发现用户选择的mimeType,并将获得对原始输入数据流的访问权。
 | 
						||
 | 
						||
作为输出,该process流程将返回一个RawData, WPS会查看响应结果中的`mimeType`类型,获得对原始内容,并获取一个文件扩展名来构建文件,提供给用户下载。
 | 
						||
 | 
						||
使用RawData的流程还必须在注释中提供一些额外的元数据,以声明支持哪些mime类型,并允许流程知道在Execute请求中选择了哪些输出mime类型。注释mimeTypes和chosenMimeType放置在结果和参数注释的位置。
 | 
						||
 | 
						||
```java
 | 
						||
@DescribeResult(name = "result", description = "Output raster",
 | 
						||
                meta = {"mimeTypes=application/json,text/xml",
 | 
						||
                        "chosenMimeType=outputMimeType" })
 | 
						||
public RawData execute(
 | 
						||
        @DescribeParameter(name = "data",
 | 
						||
                           meta = { "mimeTypes=text/plain" })
 | 
						||
                           final RawData input,
 | 
						||
        @DescribeParameter(name = "outputMimeType", min = 0)
 | 
						||
                           final String outputMimeType) {
 | 
						||
```
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
## 参考文章
 | 
						||
 | 
						||
[1] WPS design guide https://docs.geoserver.org/latest/en/developer/programming-guide/wps-services/design-guide.html
 | 
						||
 | 
						||
[2] Implementing a WPS Process https://docs.geoserver.org/latest/en/developer/programming-guide/wps-services/implementing.html
 | 
						||
 |