1. 引言
GeoServer 是一个基于 Java 的开源地理信息服务器,用于发布、共享和编辑地图数据。在实际项目中,我们往往需要将 GeoServer 的能力嵌入到自己的 SpringBoot 应用中,实现地图服务的自动化发布与管理。本文将介绍如何在 SpringBoot 项目中集成 GeoServer 源码,并实现地图服务的发布。
2. 集成方式概述
SpringBoot 集成 GeoServer 主要有两种方式:
- REST API 方式:通过调用 GeoServer 提供的 RESTful 接口进行数据发布和管理,适合与独立部署的 GeoServer 服务交互。
- 源码嵌入方式:将 GeoServer 的核心模块作为依赖引入 SpringBoot 项目,在应用内部直接调用 GeoServer 的 API 完成发布,适合深度定制和一体化部署。
本文重点介绍第二种方式,即源码集成。
3. 环境准备
在开始之前,需要准备以下环境:
- JDK 1.8 或以上版本
- Maven 3.6 或以上版本
- SpringBoot 2.x 或 3.x 项目
- GeoServer 源码(建议使用 2.19.x 或 2.20.x 稳定版本)
4. 引入 GeoServer 依赖
在 SpringBoot 项目的 pom.xml 中引入 GeoServer 相关依赖。GeoServer 的模块较多,这里只引入发布所需的核心模块:
xml
<dependency>
<groupId>org.geoserver</groupId>
<artifactId>gs-main</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>org.geoserver</groupId>
<artifactId>gs-wms</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>org.geoserver</groupId>
<artifactId>gs-wfs</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>org.geoserver</groupId>
<artifactId>gs-rest</artifactId>
<version>2.20.0</version>
</dependency>
注意:GeoServer 的依赖较多,如果遇到依赖冲突,可以通过排除传递依赖或调整版本解决。
5. 初始化 GeoServer 上下文
GeoServer 的运行依赖 Spring 上下文。在 SpringBoot 中,我们需要手动初始化 GeoServer 的上下文。可以创建一个配置类来完成初始化:
java
import org.geoserver.config.GeoServer;
import org.geoserver.config.GeoServerInfo;
import org.geoserver.config.impl.GeoServerImpl;
import org.geoserver.platform.GeoServerResourceLoader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.File;
@Configuration
public class GeoServerConfig {
@Bean
public GeoServer geoServer() throws Exception {
// 指定数据目录
File dataDir = new File("./geoserver_data");
if (!dataDir.exists()) {
dataDir.mkdirs();
}
GeoServerResourceLoader resourceLoader = new GeoServerResourceLoader(dataDir);
GeoServer geoServer = new GeoServerImpl();
geoServer.setResourceLoader(resourceLoader);
GeoServerInfo info = geoServer.getFactory().createGlobal();
info.setId("global");
geoServer.setGlobal(info);
return geoServer;
}
}
6. 实现数据发布
初始化完成后,就可以通过 GeoServer 的 API 实现数据发布。下面以发布一个 Shapefile 为例:
java
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.catalog.impl.CatalogImpl;
import org.geoserver.config.GeoServer;
import org.springframework.stereotype.Service;
import java.io.File;
@Service
public class LayerPublishService {
private final GeoServer geoServer;
public LayerPublishService(GeoServer geoServer) {
this.geoServer = geoServer;
}
public void publishShapefile(String workspaceName, String storeName, String layerName, File shapefile) throws Exception {
Catalog catalog = geoServer.getCatalog();
// 创建工作区
WorkspaceInfo workspace = catalog.getWorkspaceByName(workspaceName);
if (workspace == null) {
workspace = catalog.getFactory().createWorkspace();
workspace.setName(workspaceName);
catalog.add(workspace);
}
// 创建数据存储
DataStoreInfo store = catalog.getDataStoreByName(workspaceName, storeName);
if (store == null) {
store = catalog.getFactory().createDataStore();
store.setName(storeName);
store.setWorkspace(workspace);
store.getConnectionParameters().put("url", "file:" + shapefile.getAbsolutePath());
store.getConnectionParameters().put("namespace", workspaceName);
catalog.add(store);
}
// 创建图层
ResourceInfo resource = catalog.getResourceByName(workspaceName, layerName, ResourceInfo.class);
if (resource == null) {
resource = catalog.getFactory().createFeatureType();
resource.setName(layerName);
resource.setStore(store);
resource.setNamespace(workspace);
catalog.add(resource);
}
LayerInfo layer = catalog.getLayerByName(layerName);
if (layer == null) {
layer = catalog.getFactory().createLayer();
layer.setResource(resource);
layer.setName(layerName);
catalog.add(layer);
}
}
}
7. 发布 PostGIS 数据源
除了 Shapefile,实际项目中更常用的是发布 PostGIS 数据库中的数据。发布 PostGIS 数据源的代码如下:
java
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.config.GeoServer;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class PostGisPublishService {
private final GeoServer geoServer;
public PostGisPublishService(GeoServer geoServer) {
this.geoServer = geoServer;
}
public void publishPostGis(String workspaceName, String storeName, String host, int port,
String database, String user, String password) throws Exception {
var catalog = geoServer.getCatalog();
// 创建工作区
WorkspaceInfo workspace = catalog.getWorkspaceByName(workspaceName);
if (workspace == null) {
workspace = catalog.getFactory().createWorkspace();
workspace.setName(workspaceName);
catalog.add(workspace);
}
// 创建 PostGIS 数据存储
DataStoreInfo store = catalog.getDataStoreByName(workspaceName, storeName);
if (store == null) {
store = catalog.getFactory().createDataStore();
store.setName(storeName);
store.setWorkspace(workspace);
Map<String, String> params = new HashMap<>();
params.put("dbtype", "postgis");
params.put("host", host);
params.put("port", String.valueOf(port));
params.put("database", database);
params.put("user", user);
params.put("passwd", password);
store.getConnectionParameters().putAll(params);
catalog.add(store);
}
}
}
8. 通过 REST API 发布(备选方案)
如果不想深度耦合 GeoServer 源码,也可以使用 REST API 方式。这种方式需要先启动一个独立的 GeoServer 服务,然后通过 HTTP 请求进行发布:
java
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class GeoServerRestService {
private final RestTemplate restTemplate = new RestTemplate();
private static final String BASE_URL = "http://localhost:8080/geoserver/rest";
public void createWorkspace(String workspaceName, String username, String password) {
String url = BASE_URL + "/workspaces";
String body = "<workspace><name>" + workspaceName + "</name></workspace>";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
headers.setBasicAuth(username, password);
HttpEntity<String> entity = new HttpEntity<>(body, headers);
restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
}
public void publishLayer(String workspaceName, String storeName, String layerName,
String username, String password) {
String url = BASE_URL + "/workspaces/" + workspaceName + "/datastores/" + storeName + "/featuretypes";
String body = "<featureType><name>" + layerName + "</name></featureType>";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
headers.setBasicAuth(username, password);
HttpEntity<String> entity = new HttpEntity<>(body, headers);
restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
}
}
9. 常见问题与注意事项
- 依赖冲突 :GeoServer 依赖的库版本可能与 SpringBoot 冲突,建议使用 Maven 的
dependencyManagement统一管理版本。 - 数据目录权限:GeoServer 需要读写数据目录,部署时需确保应用有相应权限。
- 内存配置:GeoServer 对内存要求较高,建议在启动参数中适当调大 JVM 堆内存。
- 中文乱码:发布中文数据时,注意设置正确的字符编码。
10. 总结
本文介绍了在 SpringBoot 项目中集成 GeoServer 源码并实现地图服务发布的完整流程,包括依赖引入、上下文初始化、Shapefile 发布、PostGIS 数据源发布以及 REST API 备选方案。源码嵌入方式适合深度定制场景,而 REST API 方式更适合解耦部署。开发者可以根据实际业务需求选择合适的集成方式。