Spring Data JPA操作PostGIS插入地理数据报错求助
解决Spring Data JPA保存JTS几何对象到PostGIS的字节序错误
我用Leaflet绘制Point/MultiPolygon,通过Spring Data JPA存入带PostGIS的PostgreSQL。后端接收GeoJSON字符串,用自定义Jackson反序列化器转成org.locationtech.jts.geom.MultiPolygon和org.locationtech.jts.geom.Point,反序列化正常,但保存实体时触发Invalid endian flag value encountered错误。
自定义Jackson反序列化器
MultiPolygonDeserializer
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import org.locationtech.jts.geom.MultiPolygon; import java.io.IOException; import org.locationtech.jts.io.ParseException; import org.locationtech.jts.io.geojson.GeoJsonReader; public class MultiPolygonDeserializer extends JsonDeserializer<MultiPolygon> { @Override public MultiPolygon deserialize(JsonParser parser, DeserializationContext context) throws IOException { String geoJson = parser.getValueAsString(); GeoJsonReader reader = new GeoJsonReader(); try { return (MultiPolygon) reader.read(geoJson); } catch (ParseException e) { throw new IOException(e); } } }
PointDeserializer
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import org.locationtech.jts.geom.Point; import java.io.IOException; import org.locationtech.jts.io.ParseException; import org.locationtech.jts.io.geojson.GeoJsonReader; public class PointDeserializer extends JsonDeserializer<Point> { @Override public Point deserialize(JsonParser parser, DeserializationContext context) throws IOException { String geoJson = parser.getValueAsString(); GeoJsonReader reader = new GeoJsonReader(); try { return (Point) reader.read(geoJson); } catch (ParseException e) { throw new IOException(e); } } }
实体类Partner
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.pedro.geoPartners.util.MultiPolygonDeserializer; import com.pedro.geoPartners.util.PointDeserializer; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import java.util.UUID; import org.locationtech.jts.geom.MultiPolygon; import org.locationtech.jts.geom.Point; @Entity public class Partner { @Id @GeneratedValue(strategy = GenerationType.UUID) private UUID id; private String tradingName; private String ownerName; private String document; @Column(columnDefinition = "geometry(Point,4326)") @JsonDeserialize(using = PointDeserializer.class) private Point address; @Column(columnDefinition = "geometry(MultiPolygon,4326)") @JsonDeserialize(using = MultiPolygonDeserializer.class) private MultiPolygon coverageArea; // Getters and Setters public UUID getId() { return id; } public void setId(UUID id) { this.id = id; } public String getTradingName() { return tradingName; } public void setTradingName(String tradingName) { this.tradingName = tradingName; } public String getOwnerName() { return ownerName; } public void setOwnerName(String ownerName) { this.ownerName = ownerName; } public String getDocument() { return document; } public void setDocument(String document) { this.document = document; } public Point getAddress() { return address; } public void setAddress(Point address) { this.address = address; } public MultiPolygon getCoverageArea() { return coverageArea; } public void setCoverageArea(MultiPolygon coverageArea) { this.coverageArea = coverageArea; } }
错误日志
2023-03-04T17:51:39.152-03:00 WARN 116266 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: XX000 2023-03-04T17:51:39.152-03:00 ERROR 116266 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: Invalid endian flag value encountered. 2023-03-04T17:51:39.152-03:00 INFO 116266 --- [nio-8080-exec-1] o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements 2023-03-04T17:51:39.157-03:00 ERROR 116266 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.orm.jpa.JpaSystemException: could not execute statement] with root cause org.postgresql.util.PSQLException: ERROR: Invalid endian flag value encountered. at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2676) ~[postgresql-42.5.4.jar:42.5.4] at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2366) ~[postgresql-42.5.4.jar:42.5.4] at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:356) ~[postgresql-42.5.4.jar:42.5.4] at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:496) ~[postgresql-42.5.4.jar:42.5.4]...
配置信息
application.properties
spring.jpa.database=POSTGRESQL spring.datasource.url=jdbc:postgresql://localhost:5432/GeoPartners?useTimeZone=true&serverTimezone=UTC&autoReconnect=true&useSSL=false spring.datasource.username=postgres spring.datasource.password=:) spring.datasource.testWhileIdle=true spring.datasource.validationQuery=SELECT 1 spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy spring.sql.init.mode=ALWAYS spring.jpa.defer-datasource-initialization=true hibernate.dialect=org.hibernate.spatial.dialect.postgis.PostgisDialect
pom.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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.0.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.pedro</groupId> <artifactId>geoPartners</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>geoPartners</name> <description>update of "JavaWebProject", implementing new features and Front-end</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-spatial</artifactId> <version>5.4.32.Final</version> </dependency> <dependency> <groupId>org.locationtech.jts.io</groupId> <artifactId>jts-io-common</artifactId> <version>1.19.0</version> </dependency> <dependency> <groupId>org.postgis</groupId> <artifactId>postgis-jdbc</artifactId> <version>1.3.3</version> </dependency> </dependencies> <repositories> <repository> <id>osgeo-alt</id> <url>https://repo.osgeo.org/repository/release/</url> </repository> <repository> <id>geomajas</id> <name>Geomajas Maven Repository</name> <url>http://maven.geomajas.org/(http://maven.geomajas.org/)</url> </repository> </repositories> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
解决方案
这个错误由依赖版本不兼容、Hibernate Spatial配置错误以及几何对象SRID缺失共同导致,按以下步骤修复:
调整依赖版本,移除冲突依赖
- Spring Boot 3.x对应Hibernate 6.x,当前使用的Hibernate Spatial 5.4.x版本过低,存在兼容性问题。移除
org.postgis:postgis-jdbc依赖,Hibernate Spatial会自动处理PostGIS的JDBC适配。 - 修改
hibernate-spatial依赖,使用Spring Boot 3.x兼容的版本,或直接让Spring Boot管理版本:<dependency> <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-spatial</artifactId> </dependency> - 升级
jts-io-common到2.0.0及以上版本,确保与Hibernate Spatial兼容:<dependency> <groupId>org.locationtech.jts.io</groupId> <artifactId>jts-io-common</artifactId> <version>2.0.0</version> </dependency>
- Spring Boot 3.x对应Hibernate 6.x,当前使用的Hibernate Spatial 5.4.x版本过低,存在兼容性问题。移除
修正Hibernate方言配置
Spring Boot 3.x下需指定完整配置前缀,修改application.properties中的方言配置:spring.jpa.properties.hibernate.dialect=org.hibernate.spatial.dialect.postgis.PostgisDialect为几何对象设置SRID
反序列化后的JTS几何对象默认无SRID,需手动指定与数据库列一致的4326:// MultiPolygonDeserializer修改后 @Override public MultiPolygon deserialize(JsonParser parser, DeserializationContext context) throws IOException { String geoJson = parser.getValueAsString(); GeoJsonReader reader = new GeoJsonReader(); try { MultiPolygon polygon = (MultiPolygon) reader.read(geoJson); polygon.setSRID(4326); return polygon; } catch (ParseException e) { throw new IOException(e); } }// PointDeserializer修改后 @Override public Point deserialize(JsonParser parser, DeserializationContext context) throws IOException { String geoJson = parser.getValueAsString(); GeoJsonReader reader = new GeoJsonReader(); try { Point point = (Point) reader.read(geoJson); point.setSRID(4326); return point; } catch (ParseException e) { throw new IOException(e); } }重建数据库表
先删除已生成的相关表,临时设置spring.jpa.hibernate.ddl-auto=create重新生成表结构,之后改回update。
完成以上步骤后重启应用,即可正常保存几何对象到PostGIS数据库。
内容的提问来源于stack exchange,提问作者Pedro Augusto Almeida Duarte
相关产品推荐
相关产品推荐

