1
0
فهرست منبع

不动产矢量服务

chenendian 1 هفته پیش
والد
کامیت
2388d7ddc1
1فایلهای تغییر یافته به همراه168 افزوده شده و 0 حذف شده
  1. 168 0
      siwei-modules/siwei-apply/src/main/java/com/siwei/apply/utils/ArcGisUtil.java

+ 168 - 0
siwei-modules/siwei-apply/src/main/java/com/siwei/apply/utils/ArcGisUtil.java

@@ -0,0 +1,168 @@
+package com.siwei.apply.utils;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URI;
+import java.net.URLEncoder;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.nio.charset.StandardCharsets;
+import java.sql.*;
+import java.time.Duration;
+import java.util.*;
+
+
+/**
+ * arcgis rest api 工具类,支持分页查询 features、转换 rings 为 PostGIS EWKT。
+ */
+public class ArcGisUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(ArcGisUtil.class);
+    private static final int PAGE_SIZE = 1000;
+
+    private final ObjectMapper mapper = new ObjectMapper();
+
+    private final String base;
+    private final int layerId;
+    private final int srid;
+    private final HttpClient http;
+
+    public ArcGisUtil(String base, int layerId, int srid) {
+        this.base = base.endsWith("/") ? base.substring(0, base.length() - 1) : base;
+        this.layerId = layerId;
+        this.srid = srid;
+        this.http = HttpClient.newBuilder()
+                .connectTimeout(Duration.ofSeconds(15))
+                .version(HttpClient.Version.HTTP_1_1)
+                .build();
+    }
+
+
+
+    /**
+     * 拉取一页 features
+     *
+     * @param where           ArcGIS SQL92 过滤条件;查全部传 "1=1"
+     * @param returnGeometry  true=带 geometry;只要属性传 false
+     * @param offset          分页起点 (resultOffset)
+     * @param count           分页大小 (resultRecordCount),不超过服务 maxRecordCount
+     * @return 完整 query 响应(features + exceededTransferLimit)
+     */
+    public JsonNode query(String where, boolean returnGeometry, int offset, int count) throws Exception {
+        String qs = "where=" + encode(where)
+                + "&outFields=*"
+                + "&returnGeometry=" + returnGeometry
+                + "&outSR=" + srid
+                + "&resultOffset=" + offset
+                + "&resultRecordCount=" + count
+                + "&orderByFields=OBJECTID+ASC"
+                + "&f=json";
+
+        HttpRequest req = HttpRequest.newBuilder(URI.create(base + "/" + layerId + "/query?" + qs))
+                .header("Accept", "application/json")
+                .timeout(Duration.ofSeconds(120)).GET().build();
+
+        HttpResponse<String> resp = http.send(req, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
+        if (resp.statusCode() != 200) {
+            String body = resp.body();
+            throw new RuntimeException("ArcGIS HTTP " + resp.statusCode()
+                    + " : " + body.substring(0, Math.min(400, body.length())));
+        }
+        JsonNode root = mapper.readTree(resp.body());
+        if (root.has("error") && !root.get("error").isNull()) {
+            throw new RuntimeException("ArcGIS error: " + root.get("error"));
+        }
+        return root;
+    }
+
+    /**
+     * ArcGIS rings 转换为 EWKT (PostGIS 扩展)。
+     *
+     * <p>ArcGIS rings 结构 {@code [[[lng,lat],...],...]},仅取第一个环并显式闭合。
+     * 通过 JTS WKTReader 重解析几何对象,强制按右手规则确定外环,确保 PostGIS 接受。</p>
+     *
+     * <p>本实现只处理最常见的「单外环、无洞」宗地。带洞或多面的图斑需要在 GIS 工具
+     * 中合并或重绘后再入 ArcGIS 层。</p>
+     *
+     * @return 形如 {@code SRID=4490;POLYGON((x y, x y, ..., x y))},入参为空时返回 null
+     */
+    public String ringsToEwkt(JsonNode rings) throws Exception {
+        if (rings == null || !rings.isArray() || rings.isEmpty()) return null;
+        JsonNode firstRing = rings.get(0);
+        if (!firstRing.isArray() || firstRing.isEmpty()) return null;
+
+        StringBuilder pts = new StringBuilder();
+        for (int i = 0; i < firstRing.size(); i++) {
+            JsonNode pt = firstRing.get(i);
+            double x = pt.get(0).asDouble();
+            double y = pt.get(1).asDouble();
+            if (i > 0) pts.append(", ");
+            pts.append(String.format("%.6f %.6f", x, y));
+        }
+        // 显式闭合:首末相同,便于 WKTReader 严格解析
+        JsonNode head = firstRing.get(0);
+        pts.append(", ").append(String.format("%.6f %.6f", head.get(0).asDouble(), head.get(1).asDouble()));
+
+        String wkt = "POLYGON((" + pts + "))";
+        org.locationtech.jts.geom.Geometry jts =
+                new org.locationtech.jts.io.WKTReader().read(wkt);
+        return "SRID=" + srid + ";" + jts.toText();
+    }
+
+    /**
+     * 只取要素总数(用于同步前估算总量)。
+     */
+    public long count(String where) throws Exception {
+        String qs = "where=" + encode(where)
+                + "&returnCountOnly=true"
+                + "&f=json";
+        HttpRequest req = HttpRequest.newBuilder(URI.create(base + "/" + layerId + "/query?" + qs))
+                .timeout(Duration.ofSeconds(60)).GET().build();
+        HttpResponse<String> resp = http.send(req, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
+        if (resp.statusCode() != 200) {
+            throw new RuntimeException("ArcGIS HTTP " + resp.statusCode());
+        }
+        JsonNode root = mapper.readTree(resp.body());
+        return root.path("count").asLong(-1);
+    }
+
+    private static String encode(String s) {
+        return URLEncoder.encode(s, StandardCharsets.UTF_8);
+    }
+
+
+    /**
+     *
+     * @param args
+     * @throws Exception
+     */
+    public static void main(String[] args) throws Exception {
+        String arcgisBase = "http://192.168.100.1:6080/arcgis/rest/services/GJXQ/BDC_DBZD/MapServer";
+        int layerId = 0;
+        int srid = 4490;          // CGCS2000 经纬度;如取 4527(3度带)同步改这里
+        ArcGisUtil client = new ArcGisUtil(arcgisBase, layerId, srid);
+        boolean withGeometry = true;
+        //String where = "BDCDYH='360425005005GN00002W00000000'";
+        String where = "BDCDYH='360425005005GB60012W00000000'";
+        JsonNode page = client.query(where, withGeometry, 0, PAGE_SIZE);
+        JsonNode features = page.path("features");
+        //int n = features.size();
+        JsonNode f = features.get(0);
+        JsonNode attrs = f.path("attributes");
+        String ewkt = null;
+        if (withGeometry) {
+            JsonNode rings = f.path("geometry").path("rings");
+            ewkt = client.ringsToEwkt(rings);
+            log.info("ewkt OK: {} ", ewkt);
+        }
+        log.info("ArcGIS OK: {} (layer={}, srid={})", arcgisBase, layerId, srid);
+    }
+
+
+
+
+}