如何构建JPA Predicate判断点是否属于指定多边形
解决方案
核心问题出在三个点:
- 方法语义与参数顺序不匹配:
JTSSpatialPredicates.contains(a, b)语义为a包含b,你需要的是「常量多边形包含geom列的点」,而现有重载要求第二个参数必须为数据库列表达式,直接传常量多边形会类型不匹配。 - WKT解析类型不兼容:你用geolatte的WKT工具解析出来的是geolatte包的Geometry类型,和JTSSpatialPredicates要求的locationtech JTS Geometry类型不匹配。
- 属性读取写法错误:
root.get("geom").type()是获取属性的类型表达式,不是属性本身的Geometry表达式。
修正步骤
- 用JTS官方的WKT解析工具把WKT转为locationtech JTS的Geometry对象
- 两种实现方案二选一即可:
- 方案1:用
within语义适配重载:判断点geom在多边形范围内,刚好匹配第二个参数为列表达式、第三个为常量的重载 - 方案2:把常量多边形转为Criteria字面量表达式,直接用
contains方法
- 方案1:用
- 改用List存储Predicate避免空值报错
完整修正代码
import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.io.ParseException; import org.locationtech.jts.io.WKTReader; import org.hibernate.spatial.predicate.JTSSpatialPredicates; import javax.persistence.criteria.Predicate; import java.util.ArrayList; import java.util.List; public List<EComparable> searchByParams(SearchFormDto searchFormDto) throws ParseException { var cb = entityManager.getCriteriaBuilder(); var query = cb.createQuery(EComparable.class); var root = query.from(EComparable.class); List<Predicate> predicateList = new ArrayList<>(); // 解析WKT为JTS Geometry对象,注意和数据库geom列的SRID保持一致 WKTReader wktReader = new WKTReader(); Geometry polygon = wktReader.read("POLYGON ((10 10, 10 20, 20 20, 20 15, 10 10))"); // 手动设置SRID,要和数据库geom字段的SRID一致,比如WGS84坐标系填4326 // polygon.setSRID(4326); // 方案1:用within,语义:geom字段的点在polygon范围内,参数完全匹配重载 predicateList.add(JTSSpatialPredicates.within( cb, root.get("geom"), // 数据库geom列的Expression<Point> polygon // 常量多边形 )); // 方案2:如果一定要用contains,把常量转成字面量Expression即可 // predicateList.add(JTSSpatialPredicates.contains( // cb, // cb.literal(polygon), // 把常量多边形转成Expression // root.get("geom") // )); // 其他Predicate逻辑直接add到predicateList即可 query.select(root).where(predicateList.toArray(new Predicate[0])); return entityManager.createQuery(query).getResultList(); }
注意事项
- 实体类的
geom字段要定义为org.locationtech.jts.geom.Point类型,列注解参考:@Column(columnDefinition = "geometry(Point,4326)") private Point geom; - 确保项目引入了
hibernate-spatial依赖,版本要和当前Spring Boot内置的Hibernate版本一致,避免兼容性问题 - 多边形和geom字段的SRID必须一致,否则会导致空间索引失效、查询结果错误
内容的提问来源于stack exchange,提问作者Vlad
相关产品推荐
相关产品推荐

