OpenLayers 从后端服务加载 GeoJSON 数据

前言

在现代GIS开发中,OpenLayers 作为强大的前端地图库,与后端服务的无缝集成是实现动态空间数据可视化的关键。GeoJSON 作为一种轻量级的地理数据交换格式,因其结构清晰、兼容性强,成为前后端传输空间数据的首选方案。

本文将详细介绍如何通过 OpenLayers 从后端服务(Spring Boot)高效加载 GeoJSON 数据。

1. 搭建SpringBoot后端服务

开发环境

时间:2025年

GeoTools:34-SNAPSHOT

IDE:IDEA2025.1.2

JDK:17

创建好SpringBoot项目后配置数据库连接信息:

ini 复制代码
spring.application.name=geotools-boot

# src/main/resources/application.properties
server.port=8080
spring.datasource.url=jdbc:postgresql://localhost:5432/geodata?useSSL=false
spring.datasource.username=postgres
spring.datasource.password=123456
spring.jpa.hibernate.ddl-auto=update

pom.xml文件中安装GeoTools所需依赖。

xml 复制代码
<!-- GeoTools依赖 -->
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-main</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-shapefile</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-swing</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-xml</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools.xsd</groupId>
    <artifactId>gt-xsd-kml</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-geojson</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools.jdbc</groupId>
    <artifactId>gt-jdbc-postgis</artifactId>
    <version>${geotools.version}</version>
</dependency>
<!-- PostgreSQL 驱动 -->
<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.7.3</version>
</dependency>

创建省级行政区实体对象Province

less 复制代码
public class Province {
    @Setter
    @Getter
    public Integer gid;
    @Setter
    @Getter
    public String name;
    @Setter
    @Getter
    public String layer;
    @Setter
    @Getter
    public BigDecimal kind;
    @Setter
    @Getter
    public BigDecimal admincode;
    @Setter
    @Getter
    public String geom;
}

添加读取PostGIS空间数据实现类,使用GeometryJSON类将几何字段数据转换为GeoJSON数据。

ini 复制代码
@Service
public class PgService {

    public List<Province> readSpatialData() throws Exception{

        // 连接PostGIS数据库
        Map<String, Object> pgParams = new HashMap<>();
        pgParams.put(PostgisNGDataStoreFactory.DBTYPE.key, "postgis");
        pgParams.put(PostgisNGDataStoreFactory.HOST.key, "localhost");
        pgParams.put(PostgisNGDataStoreFactory.PORT.key, "5432");
        pgParams.put(PostgisNGDataStoreFactory.DATABASE.key, "geodata");
        pgParams.put(PostgisNGDataStoreFactory.USER.key, "postgres");
        pgParams.put(PostgisNGDataStoreFactory.PASSWD.key, "123456");
        pgParams.put(PostgisNGDataStoreFactory.SCHEMA.key, "public"); // 明确指定schema
        pgParams.put(PostgisNGDataStoreFactory.EXPOSE_PK.key, true);  // 暴露主键

        DataStore dataStore = DataStoreFinder.getDataStore(pgParams);
        // 数据库表名称
        String typeName = "province";
        SimpleFeatureSource featureSource = dataStore.getFeatureSource(typeName);

        // 返回数据列表
        List<Province> provinces = new ArrayList<>();

        try(FeatureIterator<SimpleFeature> features = featureSource.getFeatures().features()) {
            while (features.hasNext()) {
                SimpleFeature feature = features.next();
                Province province = new Province();
                // 添加要素
                province.setGid((Integer) feature.getAttribute("gid"));
                province.setName((String) feature.getAttribute("name"));
                province.setLayer((String) feature.getAttribute("layer"));
                province.setAdmincode((BigDecimal) feature.getAttribute("admincode"));
                Object geometry = feature.getAttribute("geom");

                // 读取几何字段数据为GeoJSON字符串
                GeometryJSON geometryJSON = new GeometryJSON();
                StringWriter writer = new StringWriter();

                geometryJSON.write((Geometry) geometry,writer);
                String jsonString = writer.toString();
                province.setGeom(jsonString);

                provinces.add(province);
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        dataStore.dispose();
        return provinces;
    }
}

编写控制类ReadPgController读取空间数据列表接口,使用@CrossOrigin(origins = "*")注解允许前端访问,不然会报跨域。

less 复制代码
/**
 * 获取空间数据列表
 */
@CrossOrigin(origins = "*") // 或指定前端地址
@RestController
public class ReadPgController {

    @Autowired
    private PgService pgService;

    @GetMapping("/spatial/list")
    public List<Province> getProviceList() throws Exception{
        return pgService.readSpatialData();
    }
}

2. 使用OpenLayers加载数据

具体使用情况请参考之前的文章:OpenLayers 加载GeoJSON的五种方式

在前端中读取后端数据可以使用原生XMLHttpRequest()请求实现,也可以通过引入第三方库Axios实现,本文使用更简单的fetch API请求。

javascript 复制代码
// 后端服务地址
const JSON_URL = "http://127.0.0.1:8080/spatial/list"
fetch(JSON_URL)
  .then(response => response.json()
  .then(result => {
    // console.log(result)

    // 读取Feature要素
    const features = result.map(item => {
      const feat = {}
      feat.type = "Feature"
      feat.geometry = JSON.parse(item.geom)
      feat.properties = item
      feat.properties.color = `hsl(${Math.floor(Math.random() * 360)}, 100%, 50%)`
      const feature = new ol.format.GeoJSON().readFeature(feat)
      return feature
    })
    const vectorSource = new ol.source.Vector({
      features: features,
      format: new ol.format.GeoJSON()
    })

    // 行政区矢量图层
    const regionLayer = new ol.layer.Vector({
      source: vectorSource,
      style: {
        'fill-color': ['string', ['get', 'color'], '#eee'],
      }
    })

    regionLayer.set("title", "云南行政区")
    map.addLayer(regionLayer)
    map.getView().setCenter([108.76623301275802, 34.22939602197002])
    map.getView().setZoom(4.5)
)

使用GeoJSON()构造矢量数据源,所以需要使用readFeature方法将Feature Object对象转换为OpenLayers Feature对象。后端返回的几何字段geom为字符串类型,所以使用JSON.parse方法将其转换为JSON对象。

在要素属性中添加color属性,设置其值为hsl随机颜色值。``feat.properties.color = `hsl(${Math.floor(Math.random() * 360)}, 100%, 50%)```

ini 复制代码
// 读取Feature要素
const features = result.map(item => {
  const feat = {}
  feat.type = "Feature"
  feat.geometry = JSON.parse(item.geom)
  feat.properties = item
  feat.properties.color = `hsl(${Math.floor(Math.random() * 360)}, 100%, 50%)`
  const feature = new ol.format.GeoJSON().readFeature(feat)
  return feature
})

设置行政区填充样式,'fill-color': ['string', ['get', 'color'], '#eee']为OpenLayers样式表达式写法,表示从color属性中获取颜色值填充要素样式,如果未获取到,则使用默认颜色值'#eee'填充。

具体可以参考文章:OpenLayers样式表达式。

php 复制代码
// 行政区矢量图层
const regionLayer = new ol.layer.Vector({
  source: vectorSource,
  style: {
    'fill-color': ['string', ['get', 'color'], '#eee'],
  }
})

表现效果如下:

OpenLayers示例数据下载,请回复关键字:ol数据

全国信息化工程师-GIS 应用水平考试资料,请回复关键字:GIS考试

【GIS之路】 已经接入了智能助手,欢迎关注,欢迎提问。

欢迎访问我的博客网站-长谈GIShttp://shanhaitalk.com

都看到这了,不要忘记点赞、收藏 + 关注

本号不定时更新有关 GIS开发 相关内容,欢迎关注 !

相关推荐
北极糊的狐36 分钟前
若依项目vue前端启动键入npm run dev 报错:不是内部或外部命令,也不是可运行的程序或批处理文件。
前端·javascript·vue.js
XRJ040618xrj38 分钟前
Nginx下构建PC站点
服务器·前端·nginx
We་ct1 小时前
LeetCode 289. 生命游戏:题解+优化,从基础到原地最优
前端·算法·leetcode·矩阵·typescript
有诺千金1 小时前
VUE3入门很简单(4)---组件通信(props)
前端·javascript·vue.js
2501_944711431 小时前
Vue-路由懒加载与组件懒加载
前端·javascript·vue.js
雨季6662 小时前
Flutter 三端应用实战:OpenHarmony “心流之泉”——在碎片洪流中,为你筑一眼专注的清泉
开发语言·前端·flutter·交互
换日线°2 小时前
前端3D炫酷展开效果
前端·3d
广州华水科技2 小时前
大坝变形监测的单北斗GNSS技术应用与发展分析
前端
Dontla2 小时前
浏览器localStorage共享机制介绍(持久化客户端存储方案)本地存储冲突、iframe、XSS漏洞、命名空间隔离
前端·网络·xss
霍理迪2 小时前
JS其他常用内置对象
开发语言·前端·javascript