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开发 相关内容,欢迎关注 !

相关推荐
辻戋2 小时前
从零实现React Scheduler调度器
前端·react.js·前端框架
徐同保2 小时前
使用yarn@4.6.0装包,项目是react+vite搭建的,项目无法启动,报错:
前端·react.js·前端框架
Qrun3 小时前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp3 小时前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.4 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
TeleostNaCl6 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫7 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友7 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理9 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻9 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js