11 Achegas 552e3ede4a ... 810188b923

Autor SHA1 Mensaxe Data
  欧阳劲驰 810188b923 增加创建圆方法(备用) hai 3 semanas
  欧阳劲驰 b1a673d3e1 增加创建圆方法(备用) hai 3 semanas
  欧阳劲驰 8428b34b4c 孤立线检查排除1组数据 hai 3 semanas
  欧阳劲驰 aa373b4188 修改超出范围检查的范围,改为按大地两千范围 hai 3 semanas
  欧阳劲驰 675f5bc05c 第三方导出增加目标坐标系处理 hai 3 semanas
  欧阳劲驰 4a7b23cd91 第三方导入增加源坐标系处理 hai 3 semanas
  欧阳劲驰 a00bdcfbfd 修复空指针 hai 3 semanas
  欧阳劲驰 900f694282 修改文件路径 hai 3 semanas
  欧阳劲驰 ff20e1687e 修改接口异常返回值 hai 3 semanas
  欧阳劲驰 bf2f3e826a 新增 坐标系转换接口 hai 3 semanas
  欧阳劲驰 11a15843b7 新增 坐标系获取列表、坐标系获取信息接口 hai 3 semanas
Modificáronse 22 ficheiros con 811 adicións e 102 borrados
  1. 41 0
      src/main/java/com/shkpr/service/alambizplugin/apiparam/GisSurveyCRSParams.java
  2. 10 0
      src/main/java/com/shkpr/service/alambizplugin/apiparam/GisSurveyThirdExportParams.java
  3. 4 0
      src/main/java/com/shkpr/service/alambizplugin/apiparam/GisSurveyThirdImportParams.java
  4. 21 24
      src/main/java/com/shkpr/service/alambizplugin/bizservice/GisSurveyThirdExportBizService.java
  5. 174 0
      src/main/java/com/shkpr/service/alambizplugin/commtools/CRSUtil.java
  6. 92 51
      src/main/java/com/shkpr/service/alambizplugin/commtools/GeomUtil.java
  7. 61 5
      src/main/java/com/shkpr/service/alambizplugin/components/GisSurveyThirdExporter.java
  8. 30 4
      src/main/java/com/shkpr/service/alambizplugin/components/GisSurveyThirdImporter.java
  9. 1 1
      src/main/java/com/shkpr/service/alambizplugin/components/checker/DuplicatePointsFinder.java
  10. 5 5
      src/main/java/com/shkpr/service/alambizplugin/components/checker/InvalidPropertiesFinder.java
  11. 9 1
      src/main/java/com/shkpr/service/alambizplugin/components/checker/IsolatedLinesFinder.java
  12. 3 0
      src/main/java/com/shkpr/service/alambizplugin/constants/ApiURI.java
  13. 14 0
      src/main/java/com/shkpr/service/alambizplugin/constants/CommCRSDefine.java
  14. 227 3
      src/main/java/com/shkpr/service/alambizplugin/controller/ApiGisSurveyController.java
  15. 3 0
      src/main/java/com/shkpr/service/alambizplugin/controllerfilter/third/ApiJWTGisSurveyBizFilter.java
  16. 0 2
      src/main/java/com/shkpr/service/alambizplugin/controllerserializer/GeometrySerializer.java
  17. 7 1
      src/main/java/com/shkpr/service/alambizplugin/dbdao/pgtype/GeomLineStringTypeHandlePg.java
  18. 5 1
      src/main/java/com/shkpr/service/alambizplugin/dbdao/pgtype/GeomPointTypeHandlePg.java
  19. 11 2
      src/main/java/com/shkpr/service/alambizplugin/dbdao/pgtype/GeomTypeHandlePg.java
  20. 36 0
      src/main/java/com/shkpr/service/alambizplugin/dto/CommCRSBoundingBox.java
  21. 55 0
      src/main/java/com/shkpr/service/alambizplugin/dto/CommCRSInfo.java
  22. 2 2
      src/main/resources/application.properties

+ 41 - 0
src/main/java/com/shkpr/service/alambizplugin/apiparam/GisSurveyCRSParams.java

@@ -0,0 +1,41 @@
+package com.shkpr.service.alambizplugin.apiparam;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.shkpr.service.alambizplugin.controllerserializer.GeometryDeserializer;
+import com.shkpr.service.alambizplugin.controllerserializer.GeometrySerializer;
+import com.shkpr.service.alambizplugin.controllervalid.CommonParamValidSK;
+import lombok.Data;
+import org.locationtech.jts.geom.Geometry;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+/**
+ * 坐标系参数
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+public class GisSurveyCRSParams {
+    /**
+     * 源crc编码
+     */
+    @NotNull(groups = {CommonParamValidSK.class})
+    @Size(max = 64, groups = {CommonParamValidSK.class})
+    private String sourceCRSCode;
+    /**
+     * 目标crc编码
+     */
+    @NotNull(groups = {CommonParamValidSK.class})
+    @Size(max = 64, groups = {CommonParamValidSK.class})
+    private String targetCRSCode;
+    /**
+     * 地理对象
+     */
+    @JsonDeserialize(using = GeometryDeserializer.class)
+    @JsonSerialize(using = GeometrySerializer.class)
+    private Geometry geometry;
+
+}

+ 10 - 0
src/main/java/com/shkpr/service/alambizplugin/apiparam/GisSurveyThirdExportParams.java

@@ -1,5 +1,7 @@
 package com.shkpr.service.alambizplugin.apiparam;
 
+import com.shkpr.service.alambizplugin.constants.CommCRSDefine;
+import com.shkpr.service.alambizplugin.constants.FileTypeEnum;
 import com.shkpr.service.alambizplugin.controllervalid.CommonParamValidSK;
 import lombok.Data;
 
@@ -27,6 +29,14 @@ public class GisSurveyThirdExportParams {
     @Size(max = 64, groups = {CommonParamValidSK.class})
     private String fileType;
     /**
+     * 文件类型枚举(内部用)
+     */
+    private FileTypeEnum fileTypeEnum;
+    /**
+     * 目标坐标系code
+     */
+    private String targetCRSCode = CommCRSDefine.CGCS2000;
+    /**
      * 操作人
      */
     @NotNull(groups = {CommonParamValidSK.class})

+ 4 - 0
src/main/java/com/shkpr/service/alambizplugin/apiparam/GisSurveyThirdImportParams.java

@@ -36,6 +36,10 @@ public class GisSurveyThirdImportParams {
      */
     private String nature;
     /**
+     * 源坐标系code
+     */
+    private String sourceCRSCode;
+    /**
      * 是否重置点号
      */
     private Boolean resetNo;

+ 21 - 24
src/main/java/com/shkpr/service/alambizplugin/bizservice/GisSurveyThirdExportBizService.java

@@ -3,11 +3,11 @@ package com.shkpr.service.alambizplugin.bizservice;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.global.base.log.LogLevelFlag;
 import com.global.base.log.LogPrintMgr;
+import com.shkpr.service.alambizplugin.apiparam.GisSurveyThirdExportParams;
 import com.shkpr.service.alambizplugin.commproperties.AsyncTaskProperties;
 import com.shkpr.service.alambizplugin.components.AsyncResultManager;
 import com.shkpr.service.alambizplugin.components.GisSurveyThirdExporter;
 import com.shkpr.service.alambizplugin.constants.CommAsyncStatusEnum;
-import com.shkpr.service.alambizplugin.constants.FileTypeEnum;
 import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
 import com.shkpr.service.alambizplugin.dbdao.services.intef.GisSurveyJobInfoService;
 import com.shkpr.service.alambizplugin.dto.CommAsyncCache;
@@ -69,42 +69,40 @@ public class GisSurveyThirdExportBizService {
     /**
      * 第三方导出
      *
-     * @param jobId    任务id
-     * @param fileType 导出文件类型
-     * @param operator 操作人
+     * @param params 导出参数
      * @return 转换结果
      */
-    public CommAsyncResult<Map<String, String>> thirdExport(String jobId, FileTypeEnum fileType, String operator) {
+    public CommAsyncResult<Map<String, String>> thirdExport(GisSurveyThirdExportParams params) {
         //获取上次结果
-        CommAsyncResult<Map<String, String>> lastResult = getTempResult(jobId);
+        CommAsyncResult<Map<String, String>> lastResult = getTempResult(params.getJobId());
         //失败/进行中处理
         if (lastResult != null && !Objects.equals(CommAsyncStatusEnum.SUCCESS.getCode(), lastResult.getStatus()))
             return lastResult;
 
         //文件结果flag
-        final String FLAG = GisSurveyThirdExporter.RESULT_PREFIX + jobId;
+        final String FLAG = GisSurveyThirdExporter.RESULT_PREFIX + params.getJobId();
         //获取文件结果
         CommAsyncResult<Map<String, String>> fileResult = asyncResultManager.getResult(FLAG, new TypeReference<CommAsyncResult<Map<String, String>>>() {
         });
         //获取数据更新时间
-        LocalDateTime refreshTime = jobInfoService.findRefreshTime(jobId);
+        LocalDateTime refreshTime = jobInfoService.findRefreshTime(params.getJobId());
         //直接返回文件结果判断:结果\刷新时间\数据不为空,结果数据包含当前项,文件结果落后数据库
         if (fileResult != null && refreshTime != null
                 //文件结果包含数据库时间
-                && fileResult.getRefreshTimes() != null && fileResult.getRefreshTimes().containsKey(fileType.getName())
+                && fileResult.getRefreshTimes() != null && fileResult.getRefreshTimes().containsKey(params.getFileTypeEnum().getName())
                 //文件结果数据包含当前项
-                && fileResult.getData() != null && fileResult.getData().containsKey(fileType.getName())) {
+                && fileResult.getData() != null && fileResult.getData().containsKey(params.getFileTypeEnum().getName())) {
 
             //文件结果落后数据间隔
-            Duration lags = Duration.between(fileResult.getRefreshTimes().get(fileType.getName()), refreshTime);
+            Duration lags = Duration.between(fileResult.getRefreshTimes().get(params.getFileTypeEnum().getName()), refreshTime);
             //规定落后时间大于落后数据间隔(数据未落后),直接返回
             if (asyncTaskProperties.getThirdExportResultLag().compareTo(lags) >= 0) return fileResult;
         }
 
         //启动任务
-        startTask(jobId, fileType, operator);
+        startTask(params);
         //返回进行中
-        return CommAsyncResult.inProgress(jobId, LocalDateTime.now(), operator);
+        return CommAsyncResult.inProgress(params.getJobId(), LocalDateTime.now(), params.getOperator());
 
     }
 
@@ -174,33 +172,32 @@ public class GisSurveyThirdExportBizService {
     /**
      * 启动任务
      *
-     * @param jobId    任务id
-     * @param fileType 导出文件类型
-     * @param operator 操作人
+     * @param params 导出参数
      */
-    private void startTask(String jobId, FileTypeEnum fileType, String operator) {
+    private void startTask(GisSurveyThirdExportParams params) {
         //获取已存在的任务
-        ListenableFuture<CommAsyncResult<Map<String, String>>> previousFuture = TASK_CACHE.get(jobId);
+        ListenableFuture<CommAsyncResult<Map<String, String>>> previousFuture = TASK_CACHE.get(params.getJobId());
         //已结束判断,删除缓存
-        if (previousFuture != null && (previousFuture.isDone() || previousFuture.isCancelled())) removeCache(jobId);
+        if (previousFuture != null && (previousFuture.isDone() || previousFuture.isCancelled()))
+            removeCache(params.getJobId());
         //执行异步任务
-        ListenableFuture<CommAsyncResult<Map<String, String>>> future = thirdExporter.thirdExportTask(jobId, fileType, operator);
+        ListenableFuture<CommAsyncResult<Map<String, String>>> future = thirdExporter.thirdExportTask(params);
         //任务超时
         taskScheduler.schedule(() -> {
             if (!future.isCancelled() && !future.isDone() && stopTask(future)) {
-                removeCache(jobId);
+                removeCache(params.getJobId());
                 LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName
                         , String.format(
                                 "第三方导出超时,成功停止任务;任务id: %s"
-                                , jobId
+                                , params.getJobId()
                         )
                 );
             }
         }, Instant.now().plusMillis(asyncTaskProperties.getThirdExportTimeout().toMillis()));
         //缓存任务句柄
-        TASK_CACHE.put(jobId, future);
+        TASK_CACHE.put(params.getJobId(), future);
         //缓存时间
-        INFO_CACHE.put(jobId, new CommAsyncCache(LocalDateTime.now(), operator));
+        INFO_CACHE.put(params.getJobId(), new CommAsyncCache(LocalDateTime.now(), params.getOperator()));
     }
 
     /**

+ 174 - 0
src/main/java/com/shkpr/service/alambizplugin/commtools/CRSUtil.java

@@ -0,0 +1,174 @@
+package com.shkpr.service.alambizplugin.commtools;
+
+import com.global.base.log.LogLevelFlag;
+import com.global.base.log.LogPrintMgr;
+import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
+import com.shkpr.service.alambizplugin.dto.CommCRSBoundingBox;
+import com.shkpr.service.alambizplugin.dto.CommCRSInfo;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.geotools.geometry.jts.JTS;
+import org.geotools.metadata.iso.extent.GeographicBoundingBoxImpl;
+import org.geotools.referencing.CRS;
+import org.geotools.referencing.ReferencingFactoryFinder;
+import org.geotools.referencing.crs.DefaultGeographicCRS;
+import org.geotools.referencing.factory.epsg.DirectEpsgFactory;
+import org.locationtech.jts.geom.Geometry;
+import org.opengis.metadata.Identifier;
+import org.opengis.referencing.FactoryException;
+import org.opengis.referencing.crs.CRSAuthorityFactory;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.datum.GeodeticDatum;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.util.GenericName;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * crs工具
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public class CRSUtil {
+    /**
+     * log
+     */
+    private final static String mStrClassName = "CRSUtil";
+    private final static String mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue();
+
+    /**
+     * 坐标系所属系统
+     */
+    private final static String AUTHORITY = "EPSG";
+    /**
+     * 坐标系工厂
+     */
+    private final static CRSAuthorityFactory crsFactory = ReferencingFactoryFinder.getCRSAuthorityFactory(AUTHORITY, null);
+
+    /**
+     * 获取坐标系列表
+     * <p>此处从 {@code HSQL} 数据库读取crs信息</br>
+     * {@link DirectEpsgFactory} 会在首次查询后缓存,所以每次从{@link CRSAuthorityFactory}获取即可</p>
+     *
+     * @return 坐标系列表
+     * @see DirectEpsgFactory#getAuthorityCodes
+     * @see org.geotools.referencing.factory.epsg.AuthorityCodes
+     */
+    public static List<Item> getList() {
+        try {
+            List<Item> results = new ArrayList<>();
+
+            //获取code集合,遍历获取描述信息
+            Set<String> codes = crsFactory.getAuthorityCodes(CoordinateReferenceSystem.class);
+            for (String code : codes) {
+                code = code.trim();
+                String desc = crsFactory.getDescriptionText(AUTHORITY + ":" + code).toString();
+
+                results.add(new Item(code, desc));
+            }
+
+            return results;
+        } catch (FactoryException e) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                    , String.format("CRS解析异常: error:%s", e));
+            return Collections.emptyList();
+        }
+    }
+
+    /**
+     * 获取坐标系信息
+     *
+     * @param code 坐标系code
+     * @return 坐标系信息
+     */
+    public static CommCRSInfo getInfo(String code) {
+        try {
+            //获取code集合
+            Set<String> codes = crsFactory.getAuthorityCodes(CoordinateReferenceSystem.class);
+            if (!codes.contains(code)) return null;
+            //获取crs
+            CoordinateReferenceSystem crs = CRS.decode(AUTHORITY + ":" + code, true);
+            if (crs == null) return null;
+            //构建结果
+            CommCRSInfo result = new CommCRSInfo();
+            //基本信息
+            if (crs.getName() != null) result.setName(crs.getName().getCode());
+            if (crs.getIdentifiers() != null)
+                result.setCode(crs.getIdentifiers().stream().map(Identifier::getCode).collect(Collectors.joining(",")));
+            if (crs.getCoordinateSystem() != null) result.setDimension(crs.getCoordinateSystem().getDimension());
+            if (crs.getRemarks() != null) result.setRemarks(crs.getRemarks().toString());
+            if (crs.getAlias() != null)
+                result.setAlias(crs.getAlias().stream().map(GenericName::toString).collect(Collectors.toList()));
+            result.setWkt(crs.toWKT());
+            //范围
+            if (crs.getDomainOfValidity() != null) {
+                if (crs.getDomainOfValidity().getGeographicElements() != null)
+                    result.setBoundingBoxes(crs.getDomainOfValidity().getGeographicElements().stream()
+                            .filter(it -> it instanceof GeographicBoundingBoxImpl)
+                            .map(it -> {
+                                GeographicBoundingBoxImpl boundingBox = (GeographicBoundingBoxImpl) it;
+                                return BeanUtil.copy(boundingBox, CommCRSBoundingBox.class);
+                            }).collect(Collectors.toList()));
+                if (crs.getDomainOfValidity().getDescription() != null)
+                    result.setBoundingBoxDescription(crs.getDomainOfValidity().getDescription().toString());
+
+            }
+            //基准
+            if (crs instanceof DefaultGeographicCRS) {
+                GeodeticDatum datum = ((DefaultGeographicCRS) crs).getDatum();
+                if (datum != null) {
+                    if (datum.getName() != null) result.setDatumName(datum.getName().getCode());
+                    if (datum.getIdentifiers() != null)
+                        result.setDatumCode(datum.getIdentifiers().stream().map(Identifier::getCode).collect(Collectors.joining(",")));
+                }
+            }
+
+            return result;
+        } catch (FactoryException e) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                    , String.format("CRS解析异常: error:%s", e));
+            return null;
+        }
+    }
+
+    /**
+     * 转换
+     *
+     * @param geometry      源地理对象
+     * @param sourceCRSCode 源坐标系code
+     * @param targetCRSCode 目标坐标系code
+     * @return 转换后地理对象
+     */
+    public static Geometry transform(Geometry geometry, String sourceCRSCode, String targetCRSCode) {
+        try {
+            //获取crs
+            CoordinateReferenceSystem sourceCRS = CRS.decode(AUTHORITY + ":" + sourceCRSCode, true);
+            CoordinateReferenceSystem targetCRS = CRS.decode(AUTHORITY + ":" + targetCRSCode, true);
+            //获取转换器
+            MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, true);
+            // 转换对象
+            Geometry transformedGeometry = JTS.transform(geometry, transform);
+            // 设置 CRS
+            transformedGeometry.setSRID(Integer.parseInt(targetCRSCode));
+            return transformedGeometry;
+        } catch (FactoryException | TransformException e) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                    , String.format("geom转换异常: error:%s", e));
+            return null;
+        }
+    }
+
+
+    @Data
+    @AllArgsConstructor
+    public static class Item {
+        String code;
+        String desc;
+    }
+}

+ 92 - 51
src/main/java/com/shkpr/service/alambizplugin/commtools/GeomUtil.java

@@ -1,76 +1,117 @@
 package com.shkpr.service.alambizplugin.commtools;
 
+import com.global.base.log.LogLevelFlag;
+import com.global.base.log.LogPrintMgr;
+import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
+import org.geotools.referencing.CRS;
+import org.geotools.referencing.GeodeticCalculator;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Envelope;
 import org.locationtech.jts.geom.GeometryFactory;
-import org.locationtech.jts.geom.Point;
-import org.locationtech.jts.geom.PrecisionModel;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
+import org.locationtech.jts.geom.Polygon;
+import org.locationtech.jts.util.GeometricShapeFactory;
+import org.opengis.referencing.FactoryException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.TransformException;
 
 /**
  * 地理工具类
  *
  * @author 欧阳劲驰
- * @since JDK1.8
+ * @since 1.0.0
  */
 public class GeomUtil {
     /**
+     * log
+     */
+    private final static String mStrClassName = "GeomUtil";
+    private final static String mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue();
+    /**
      * geom工厂
      */
-    private static final GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 4490);
+    private static final GeometryFactory geometryFactory = new GeometryFactory();
     /**
-     * 地球半径
+     * 形状工厂
      */
-    private static final int EARTH_RADIUS = 6378137;
+    private final static GeometricShapeFactory shapeFactory = new GeometricShapeFactory(geometryFactory);
 
     /**
-     * 将米转换为度
+     * 创建圆
      *
-     * @param degrees 度
-     * @return 对应的米
+     * @param centre  圆心
+     * @param radius  半径
+     * @param crsCode 坐标系
+     * @return 圆
      */
-    public static double convertDegreesToMeters(double degrees) {
-        return degrees * (Math.PI / 180) * EARTH_RADIUS;
-    }
+    public static Polygon createCircle(Coordinate centre, double radius, String crsCode) {
+        try {
+            //端点数量
+            int extremePointsTotal = 32;
+            //经度
+            double lng = centre.getX();
+            //纬度
+            double lat = centre.getY();
+            //坐标系
+            CoordinateReferenceSystem crs = CRS.decode("EPSG:" + crsCode);
+            if (crs == null) return null;
 
+            //创建大地计算器,并设置坐标系
+            GeodeticCalculator gc = new GeodeticCalculator(crs);
 
-    /**
-     * 将米转换为度
-     *
-     * @param meters 米
-     * @return 对应的度
-     */
-    public static double convertMetersToDegrees(double meters) {
-        return meters / (Math.PI / 180 * EARTH_RADIUS);
-    }
+            //计算东点(90度),正东移动
+            gc.setStartingGeographicPoint(lng, lat);
+            gc.setDirection(90, radius);
+            //获取结果
+            double[] eastCoords = gc.getDestinationPosition().getCoordinate();
+            Coordinate eastPoint = new Coordinate(eastCoords[1], eastCoords[0]); // 创建 Coordinate 对象
 
-    /**
-     * 经纬度的度转十进制
-     * <p>如RMC(NMEA0183)协议报文:</p>
-     * <blockquote><pre>$GNRMC,072905.00,A,3640.46260,N,11707.54950,E,000.0,000.0,050119,OK*24</pre></blockquote>
-     * <p>则表示为:{@code [36.67438,117.12583]}</p>
-     *
-     * @param degrees      度
-     * @param minutesIndex 分索引,如 {@code  ddmm.mmmmm} 则为2
-     * @return 十进制表示
-     */
-    public static double convertDegreesToDecimal(String degrees, int minutesIndex) {
-        return Integer.parseInt(degrees.substring(0, minutesIndex)) +
-                //分除60保留8位
-                BigDecimal.valueOf(Float.parseFloat(degrees.substring(minutesIndex)))
-                        .divide(BigDecimal.valueOf(60), 8, RoundingMode.HALF_UP)
-                        .doubleValue();
-    }
+            //计算西点(270度),正西移动
+            gc.setStartingGeographicPoint(lng, lat);
+            gc.setDirection(270, radius);
+            //获取结果
+            double[] westCoords = gc.getDestinationPosition().getCoordinate();
+            Coordinate westPoint = new Coordinate(westCoords[1], westCoords[0]);
 
-    /**
-     * 判断点1是否在点2距离范围内
-     *
-     * @param point1   点1
-     * @param point2   点2
-     * @param distance 距离(米)
-     * @return 判断状态
-     */
-    public static Boolean isWithinDistance(Point point1, Point point2, double distance) {
-        return point1.isWithinDistance(point2, convertMetersToDegrees(distance));
+            //计算北点(0度),正北移动
+            gc.setStartingGeographicPoint(lng, lat);
+            gc.setDirection(0, radius);
+            //获取结果
+            double[] northCoords = gc.getDestinationPosition().getCoordinate();
+            Coordinate northPoint = new Coordinate(northCoords[1], northCoords[0]);
+
+            //计算南点(180度)
+            gc.setStartingGeographicPoint(lng, lat);
+            gc.setDirection(180, radius);
+            //获取结果
+            double[] southCoords = gc.getDestinationPosition().getCoordinate();
+            Coordinate southPoint = new Coordinate(southCoords[1], southCoords[0]);
+
+            //创建边界框
+            double x1 = westPoint.x;
+            double x2 = eastPoint.x;
+            double y1 = southPoint.y;
+            double y2 = northPoint.y;
+            Envelope envelope = new Envelope(x1, x2, y1, y2);
+
+            //设置圆心
+            Coordinate coordinate = new Coordinate(lng, lat);
+            shapeFactory.setCentre(coordinate);
+            //设置边界
+            shapeFactory.setEnvelope(envelope);
+            //设置边界点数量
+            shapeFactory.setNumPoints(extremePointsTotal);
+
+            //创建圆
+            Polygon circle = shapeFactory.createCircle();
+            //设置坐标系
+            circle.setSRID(Integer.parseInt(crsCode));
+
+            return circle;
+        } catch (TransformException | FactoryException e) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                    , String.format("geom创建失败: error:%s", e));
+
+            return null;
+        }
     }
 }

+ 61 - 5
src/main/java/com/shkpr/service/alambizplugin/components/GisSurveyThirdExporter.java

@@ -3,8 +3,11 @@ package com.shkpr.service.alambizplugin.components;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.global.base.log.LogLevelFlag;
 import com.global.base.log.LogPrintMgr;
+import com.shkpr.service.alambizplugin.apiparam.GisSurveyThirdExportParams;
+import com.shkpr.service.alambizplugin.commtools.CRSUtil;
 import com.shkpr.service.alambizplugin.commtools.ThirdImportTemplateUtils;
 import com.shkpr.service.alambizplugin.constants.CommAsyncStatusEnum;
+import com.shkpr.service.alambizplugin.constants.CommCRSDefine;
 import com.shkpr.service.alambizplugin.constants.FileTypeEnum;
 import com.shkpr.service.alambizplugin.constants.GisMetadataDefine;
 import com.shkpr.service.alambizplugin.constants.GisSurveyExcelDefine;
@@ -21,6 +24,8 @@ import org.apache.commons.compress.archivers.ArchiveException;
 import org.apache.commons.lang3.StringUtils;
 import org.geotools.data.DataUtilities;
 import org.geotools.feature.SchemaException;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Geometry;
 import org.opengis.feature.simple.SimpleFeatureType;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.scheduling.annotation.AsyncResult;
@@ -28,6 +33,7 @@ import org.springframework.stereotype.Component;
 import org.springframework.util.concurrent.ListenableFuture;
 
 import java.io.IOException;
+import java.math.BigDecimal;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.time.Duration;
@@ -78,15 +84,18 @@ public class GisSurveyThirdExporter {
     /**
      * 第三方导出任务
      *
-     * @param jobId    任务id
-     * @param fileType 导出文件类型
-     * @param operator 操作人
+     * @param params 导出参数
      * @return 导出结果
      */
     @Async
-    public ListenableFuture<CommAsyncResult<Map<String, String>>> thirdExportTask(String jobId, FileTypeEnum fileType, String operator) {
+    public ListenableFuture<CommAsyncResult<Map<String, String>>> thirdExportTask(GisSurveyThirdExportParams params) {
+        //参数
+        String jobId = params.getJobId();
+        FileTypeEnum fileType = params.getFileTypeEnum();
+        String targetCRSCode = params.getTargetCRSCode();
+        String operator = params.getOperator();
         //构建返回
-        CommAsyncResult<Map<String, String>> result = CommAsyncResult.fail(jobId);
+        CommAsyncResult<Map<String, String>> result = CommAsyncResult.fail(params.getJobId());
         result.setOperator(operator);
         try {
             LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName
@@ -102,6 +111,9 @@ public class GisSurveyThirdExporter {
             List<GisSurveyLayerApply> points = gisSurveyLayerApplyService.findAllByJobIdAndKind(jobId, GisMetadataDefine.TYPE_KINE.POINT);
             List<GisSurveyLayerApply> lines = gisSurveyLayerApplyService.findAllByJobIdAndKind(jobId, GisMetadataDefine.TYPE_KINE.LINE);
 
+            //处理坐标系
+            if (!Objects.equals(targetCRSCode, CommCRSDefine.CGCS2000)) transformGeom(targetCRSCode, points, lines);
+
             //获取图层key
             List<String> pointLayer = getLayerKeys(points);
             List<String> lineLayer = getLayerKeys(lines);
@@ -184,6 +196,50 @@ public class GisSurveyThirdExporter {
     }
 
     /**
+     * 转换geom
+     *
+     * @param targetCRSCode 目标坐标系
+     * @param points        点集合
+     * @param lines         线结合
+     */
+    private void transformGeom(String targetCRSCode, List<GisSurveyLayerApply> points, List<GisSurveyLayerApply> lines) {
+        //处理点
+        points.parallelStream().forEach(point -> {
+            //获取geom
+            Geometry geometry = point.getGis();
+            if (geometry == null) return;
+            //转换geom
+            Geometry transform = CRSUtil.transform(geometry, CommCRSDefine.CGCS2000, targetCRSCode);
+            if (transform == null) return;
+            //回填元素
+            point.setGis(transform);
+            //获取解析后的经纬度
+            Coordinate coordinate = transform.getCoordinate();
+            String lngStr = BigDecimal.valueOf(coordinate.getX()).toPlainString();
+            String latStr = BigDecimal.valueOf(coordinate.getY()).toPlainString();
+            //回填经纬度属性
+            List<GisSurveyPropertyValue> propertyValues = point.getPropertyValues();
+            propertyValues.stream()
+                    .filter(it -> Objects.equals(it.getProperty(), GisSurveyExcelDefine.TEMPLATE.LAT))
+                    .forEach(it -> it.setValue(latStr));
+            propertyValues.stream()
+                    .filter(it -> Objects.equals(it.getProperty(), GisSurveyExcelDefine.TEMPLATE.LNG))
+                    .forEach(it -> it.setValue(lngStr));
+        });
+        //处理线
+        lines.parallelStream().forEach(line -> {
+            //获取geom
+            Geometry geometry = line.getGis();
+            if (geometry == null) return;
+            //转换geom
+            Geometry transform = CRSUtil.transform(geometry, CommCRSDefine.CGCS2000, targetCRSCode);
+            if (transform == null) return;
+            //回填元素
+            line.setGis(transform);
+        });
+    }
+
+    /**
      * 导出excel
      *
      * @param points              点

+ 30 - 4
src/main/java/com/shkpr/service/alambizplugin/components/GisSurveyThirdImporter.java

@@ -3,6 +3,7 @@ package com.shkpr.service.alambizplugin.components;
 import com.global.base.log.LogLevelFlag;
 import com.global.base.log.LogPrintMgr;
 import com.shkpr.service.alambizplugin.apiparam.GisSurveyThirdImportParams;
+import com.shkpr.service.alambizplugin.commtools.CRSUtil;
 import com.shkpr.service.alambizplugin.commtools.ExcelUtils;
 import com.shkpr.service.alambizplugin.commtools.PointCodeUtil;
 import com.shkpr.service.alambizplugin.commtools.ThirdImportTemplateUtils;
@@ -13,6 +14,7 @@ import com.shkpr.service.alambizplugin.components.checker.DuplicatePointsFinder;
 import com.shkpr.service.alambizplugin.components.checker.InvalidLinesFinder;
 import com.shkpr.service.alambizplugin.components.checker.InvalidPropertiesFinder;
 import com.shkpr.service.alambizplugin.constants.CommAsyncStatusEnum;
+import com.shkpr.service.alambizplugin.constants.CommCRSDefine;
 import com.shkpr.service.alambizplugin.constants.ExcelEnum;
 import com.shkpr.service.alambizplugin.constants.GisMetadataDefine;
 import com.shkpr.service.alambizplugin.constants.GisSurveyExcelDefine;
@@ -35,8 +37,8 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.math.NumberUtils;
 import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Geometry;
 import org.locationtech.jts.geom.GeometryFactory;
-import org.locationtech.jts.geom.Point;
 import org.locationtech.jts.geom.PrecisionModel;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.scheduling.annotation.AsyncResult;
@@ -451,14 +453,38 @@ public class GisSurveyThirdImporter {
                     layerApply.setDepth(Double.valueOf(propertyValue.getValue()));
             }
         }
-        layerApply.setPropertyValues(propertyValueList);
 
-        //填入经纬度
+        //处理经纬度
         if (lng != null && lat != null) {
-            Point geometry = geometryFactory.createPoint(new Coordinate(lng, lat));
+            //构建geom
+            Geometry geometry = geometryFactory.createPoint(new Coordinate(lng, lat));
+            //如源不为大地2000
+            if (!Objects.equals(params.getSourceCRSCode(), CommCRSDefine.CGCS2000)) {
+                //转换坐标系
+                Geometry transform = CRSUtil.transform(geometry, params.getSourceCRSCode(), CommCRSDefine.CGCS2000);
+                if (transform != null) {
+                    //回填geom
+                    geometry = transform;
+                    //获取解析后的经纬度
+                    Coordinate coordinate = geometry.getCoordinate();
+                    String lngStr = BigDecimal.valueOf(coordinate.getX()).toPlainString();
+                    String latStr = BigDecimal.valueOf(coordinate.getY()).toPlainString();
+                    //回填经纬度属性
+                    propertyValueList.stream()
+                            .filter(it -> Objects.equals(it.getProperty(), GisSurveyExcelDefine.TEMPLATE.LAT))
+                            .forEach(it -> it.setValue(latStr));
+                    propertyValueList.stream()
+                            .filter(it -> Objects.equals(it.getProperty(), GisSurveyExcelDefine.TEMPLATE.LNG))
+                            .forEach(it -> it.setValue(lngStr));
+                }
+            }
+            //设置geom
             layerApply.setGis(geometry);
         }
 
+        //设置属性
+        layerApply.setPropertyValues(propertyValueList);
+
         return layerApply;
     }
 

+ 1 - 1
src/main/java/com/shkpr/service/alambizplugin/components/checker/DuplicatePointsFinder.java

@@ -271,7 +271,7 @@ public class DuplicatePointsFinder {
      *
      * @param coordinate   坐标
      * @param lngScale     经度精度
-     * @param latScale     度精度
+     * @param latScale     度精度
      * @param lngTolerance 经度公差
      * @param latTolerance 纬度公差
      * @return 边界

+ 5 - 5
src/main/java/com/shkpr/service/alambizplugin/components/checker/InvalidPropertiesFinder.java

@@ -3,7 +3,6 @@ package com.shkpr.service.alambizplugin.components.checker;
 import com.global.base.log.LogLevelFlag;
 import com.global.base.log.LogPrintMgr;
 import com.shkpr.service.alambizplugin.commtools.BeanUtil;
-import com.shkpr.service.alambizplugin.commtools.GeomUtil;
 import com.shkpr.service.alambizplugin.commtools.ThirdImportTemplateUtils;
 import com.shkpr.service.alambizplugin.constants.GisMetadataDefine;
 import com.shkpr.service.alambizplugin.constants.GisSurveyExcelDefine;
@@ -39,10 +38,11 @@ public class InvalidPropertiesFinder {
     /**
      * 中国经纬度范围
      */
-    private static final Double MIN_LAT = GeomUtil.convertDegreesToDecimal("351", 1);
-    private static final Double MAX_LAT = GeomUtil.convertDegreesToDecimal("5333", 2);
-    private static final Double MIN_LNG = GeomUtil.convertDegreesToDecimal("7333", 2);
-    private static final Double MAX_LNG = GeomUtil.convertDegreesToDecimal("13505", 3);
+    private static final Double MIN_LNG = 73.62;
+    private static final Double MAX_LNG = 134.77;
+    private static final Double MIN_LAT = 16.7;
+    private static final Double MAX_LAT = 53.56;
+
     /**
      * log
      */

+ 9 - 1
src/main/java/com/shkpr/service/alambizplugin/components/checker/IsolatedLinesFinder.java

@@ -19,6 +19,8 @@ import org.springframework.util.concurrent.ListenableFuture;
 
 import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -178,7 +180,13 @@ public class IsolatedLinesFinder {
                         //转为返回元素
                         .add(BeanUtil.copy(line, GisSurveySystemCheckElement.class));
             }
-            return new ArrayList<>(groups.values());
+
+            //分组结果值集合
+            Collection<List<GisSurveySystemCheckElement>> groupValues = groups.values();
+            //排除1组数据
+            if (groupValues.size() == 1) groupValues = Collections.emptyList();
+
+            return new ArrayList<>(groupValues);
         }
 
         /**

+ 3 - 0
src/main/java/com/shkpr/service/alambizplugin/constants/ApiURI.java

@@ -37,6 +37,9 @@ public class ApiURI {
     public static final String URI_XXX_THIRD_EXPORT_GET = "third-export-get";
     public static final String URI_XXX_CAD_CONVERT = "cad-convert";
     public static final String URI_XXX_CAD_CONVERT_GET = "cad-convert-get";
+    public static final String URI_XXX_CRS_GET_LIST = "crs-get-list";
+    public static final String URI_XXX_CRS_GET_INFO = "crs-get-info";
+    public static final String URI_XXX_CRS_TRANSFORM = "crs-transform";
     public static final String URI_XXX_TEMP_FILES = "temp-files";
     public static final String URI_XXX_ASYNC_RESULTS = "async-results";
 

+ 14 - 0
src/main/java/com/shkpr/service/alambizplugin/constants/CommCRSDefine.java

@@ -0,0 +1,14 @@
+package com.shkpr.service.alambizplugin.constants;
+
+/**
+ * 通用crs定义
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public interface CommCRSDefine {
+    /**
+     * 大地2000
+     */
+    String CGCS2000 = "4490";
+}

+ 227 - 3
src/main/java/com/shkpr/service/alambizplugin/controller/ApiGisSurveyController.java

@@ -2,8 +2,10 @@ package com.shkpr.service.alambizplugin.controller;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
 import com.global.base.log.LogLevelFlag;
 import com.global.base.log.LogPrintMgr;
+import com.shkpr.service.alambizplugin.apiparam.GisSurveyCRSParams;
 import com.shkpr.service.alambizplugin.apiparam.GisSurveyCheckParams;
 import com.shkpr.service.alambizplugin.apiparam.GisSurveyThirdExportParams;
 import com.shkpr.service.alambizplugin.apiparam.GisSurveyThirdImportParams;
@@ -11,19 +13,23 @@ import com.shkpr.service.alambizplugin.bizservice.GisSurveyCadConvertBizService;
 import com.shkpr.service.alambizplugin.bizservice.GisSurveySystemCheckBizService;
 import com.shkpr.service.alambizplugin.bizservice.GisSurveyThirdExportBizService;
 import com.shkpr.service.alambizplugin.bizservice.GisSurveyThirdImportBizService;
+import com.shkpr.service.alambizplugin.commtools.CRSUtil;
 import com.shkpr.service.alambizplugin.commtools.CommTool;
 import com.shkpr.service.alambizplugin.constants.ApiURI;
 import com.shkpr.service.alambizplugin.constants.CadEnum;
 import com.shkpr.service.alambizplugin.constants.CommAsyncStatusEnum;
+import com.shkpr.service.alambizplugin.constants.CommCRSDefine;
 import com.shkpr.service.alambizplugin.constants.FileTypeEnum;
 import com.shkpr.service.alambizplugin.constants.GisSurveyImportStatusEnum;
 import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
 import com.shkpr.service.alambizplugin.constants.ResponseCode;
 import com.shkpr.service.alambizplugin.controllerfilter.TokenAuthenticationService;
+import com.shkpr.service.alambizplugin.controllerserializer.GeometrySerializer;
 import com.shkpr.service.alambizplugin.controllervalid.CommonParamValidSK;
 import com.shkpr.service.alambizplugin.dbdao.services.GisSurveyLayerApplyThirdCopyServiceImpl;
 import com.shkpr.service.alambizplugin.dbdao.services.intef.GisSurveyLayerApplyService;
 import com.shkpr.service.alambizplugin.dto.CommAsyncResult;
+import com.shkpr.service.alambizplugin.dto.CommCRSInfo;
 import com.shkpr.service.alambizplugin.dto.GisSurveyLayerApplyThirdCopy;
 import com.shkpr.service.alambizplugin.dto.GisSurveySystemCheckResultDetail;
 import com.shkpr.service.alambizplugin.dto.GisSurveyThirdImportResult;
@@ -32,6 +38,7 @@ import com.shkpr.service.alambizplugin.dto.ResponseRes;
 import com.shkpr.service.alambizplugin.exception.SelfException;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.locationtech.jts.geom.Geometry;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.web.PageableDefault;
 import org.springframework.validation.BindingResult;
@@ -69,6 +76,8 @@ public class ApiGisSurveyController {
     private final AtomicInteger mSeqThirdExportReq;
     private final AtomicInteger mSeqThirdExportGetReq;
     private final AtomicInteger mSeqCadConvertGetReq;
+    private final AtomicInteger mSeqCrsGetListReq;
+    private final AtomicInteger mSeqCrsGetInfoReq;
 
     private final ObjectMapper objectMapper;
 
@@ -99,6 +108,8 @@ public class ApiGisSurveyController {
         mSeqThirdExportGetReq = new AtomicInteger(0);
         mSeqCadConvertReq = new AtomicInteger(0);
         mSeqCadConvertGetReq = new AtomicInteger(0);
+        mSeqCrsGetListReq = new AtomicInteger(0);
+        mSeqCrsGetInfoReq = new AtomicInteger(0);
         this.objectMapper = objectMapper;
         this.systemCheckBizService = systemCheckBizService;
         this.thirdImportBizService = thirdImportBizService;
@@ -266,6 +277,7 @@ public class ApiGisSurveyController {
      * @param operator      操作人
      * @param jobId         任务id
      * @param nature        用水性质,supply/drain
+     * @param sourceCRSCode 源坐标系code
      * @param resetNo       是否重置点号
      * @param ignoreFail    是否忽略失败
      * @return 第三方导入结果
@@ -278,6 +290,7 @@ public class ApiGisSurveyController {
             , @RequestParam(value = "operator", required = false) String operator
             , @RequestParam(value = "jobId", required = false) String jobId
             , @RequestParam(value = "nature", required = false) String nature
+            , @RequestParam(value = "sourceCRSCode", required = false, defaultValue = CommCRSDefine.CGCS2000) String sourceCRSCode
             , @RequestParam(value = "resetNo", required = false) Boolean resetNo
             , @RequestParam(value = "checkConstraint", required = false, defaultValue = "false") Boolean checkConstraint
             , @RequestParam(value = "ignoreFail", required = false, defaultValue = "false") String ignoreFail) throws SelfException {
@@ -294,7 +307,8 @@ public class ApiGisSurveyController {
                     , ResponseCode.STATUS_ERROR_PARAM_FORMAT.toStrMsg()));
         }
         //构建入参数
-        GisSurveyThirdImportParams params = new GisSurveyThirdImportParams(files, operator, jobId, nature, resetNo, checkConstraint, Boolean.parseBoolean(ignoreFail));
+        GisSurveyThirdImportParams params = new GisSurveyThirdImportParams(files, operator, jobId, nature, sourceCRSCode,
+                resetNo, checkConstraint, Boolean.parseBoolean(ignoreFail));
         //begin
         long llReqBefore = System.currentTimeMillis();
         String strRunSeq = String.format("%d-%d", llReqBefore, mSeqThirdImportReq.incrementAndGet());
@@ -673,10 +687,10 @@ public class ApiGisSurveyController {
 
         //导出类型枚举
         FileTypeEnum fileTypeEnum = FileTypeEnum.getFileType(oJsonParam.getFileType());
-        if (fileTypeEnum == null) fileTypeEnum = FileTypeEnum.EXCEL;
+        oJsonParam.setFileTypeEnum(fileTypeEnum == null ? FileTypeEnum.EXCEL : fileTypeEnum);
 
         //执行第三方导出
-        CommAsyncResult<Map<String, String>> result = thirdExportBizService.thirdExport(oJsonParam.getJobId(), fileTypeEnum, oJsonParam.getOperator());
+        CommAsyncResult<Map<String, String>> result = thirdExportBizService.thirdExport(oJsonParam);
         String resultStr = null;
         try {
             if (result != null) resultStr = objectMapper.writeValueAsString(result);
@@ -980,4 +994,214 @@ public class ApiGisSurveyController {
                         , resResult.getTimestamp() - llReqBefore));
         return resResult;
     }
+
+    /**
+     * 获取坐标系列表
+     *
+     * @param request       request
+     * @param strClientType 客户端类型
+     * @param strUserAgent  用户信息
+     * @return crs列表
+     */
+    @GetMapping(value = ApiURI.URI_XXX_CRS_GET_LIST)
+    public ResponseRes<String> crsGetList(HttpServletRequest request
+            , @RequestHeader(value = ApiURI.HEADER_CLIENT_TYPE, required = false) String strClientType
+            , @RequestHeader(value = ApiURI.HEADER_USER_AGENT, required = false) String strUserAgent) {
+        //入参校验
+        final String URI_PATH = request.getRequestURI();
+        final String strPlatform = CommTool.getPlatformByAgent(strClientType, strUserAgent);
+        final String strUserId = (String) request.getAttribute(TokenAuthenticationService.HEADER_USERID);
+
+        //begin
+        long llReqBefore = System.currentTimeMillis();
+        String strRunSeq = String.format("%d-%d", llReqBefore, mSeqCrsGetListReq.incrementAndGet());
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, strUserId
+                , String.format("%s:%s seq:{%s} begin====>"
+                        , strPlatform
+                        , URI_PATH
+                        , strRunSeq));
+
+        //构建result
+        ResponseRes<String> resResult = new ResponseRes<>();
+        resResult.setRescode(ResponseCode.RESULT_BAD.toStrCode());
+        resResult.setResmsg(ResponseCode.RESULT_BAD.toStrMsg());
+
+        //获取crs列表
+        List<CRSUtil.Item> result = CRSUtil.getList();
+        String resultStr = null;
+        try {
+            if (CollectionUtils.isNotEmpty(result)) resultStr = objectMapper.writeValueAsString(result);
+        } catch (JsonProcessingException e) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                    , String.format("Json序列化异常: error:%s", e));
+        }
+
+        //执行成功
+        if (resultStr != null) {
+            resResult.setRescode(ResponseCode.RESULT_NORMAL.toStrCode());
+            resResult.setResmsg(ResponseCode.RESULT_NORMAL.toStrMsg());
+            resResult.setResdata(resultStr);
+        }
+
+        //end
+        resResult.setTimestamp(System.currentTimeMillis());
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, strUserId
+                , String.format("%s:%s seq:{%s} rescode:{%s} resmsg:{%s} time:{%d ms} end<===="
+                        , strPlatform
+                        , URI_PATH
+                        , strRunSeq
+                        , resResult.getRescode()
+                        , resResult.getResmsg()
+                        , resResult.getTimestamp() - llReqBefore));
+        return resResult;
+    }
+
+    /**
+     * 获取坐标系信息
+     *
+     * @param request       request
+     * @param strClientType 客户端类型
+     * @param strUserAgent  用户信息
+     * @return crs信息
+     */
+    @GetMapping(value = ApiURI.URI_XXX_CRS_GET_INFO)
+    public ResponseRes<String> crsGetInfo(HttpServletRequest request
+            , @RequestHeader(value = ApiURI.HEADER_CLIENT_TYPE, required = false) String strClientType
+            , @RequestHeader(value = ApiURI.HEADER_USER_AGENT, required = false) String strUserAgent
+            , @RequestParam(value = "code", required = false) String code) throws SelfException {
+        //入参校验
+        final String URI_PATH = request.getRequestURI();
+        final String strPlatform = CommTool.getPlatformByAgent(strClientType, strUserAgent);
+        final String strUserId = (String) request.getAttribute(TokenAuthenticationService.HEADER_USERID);
+        if (StringUtils.isAnyBlank(code) || StringUtils.length(code) > 64) {
+            throw new SelfException(ResponseCode.STATUS_ERROR_PARAM_FORMAT.toStrCode()
+                    , String.format(ApiURI.EXCEPTION_FORMAT
+                    , strPlatform
+                    , URI_PATH
+                    , ResponseCode.STATUS_ERROR_PARAM_FORMAT.toStrMsg()));
+        }
+
+
+        //begin
+        long llReqBefore = System.currentTimeMillis();
+        String strRunSeq = String.format("%d-%d", llReqBefore, mSeqCrsGetInfoReq.incrementAndGet());
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, strUserId
+                , String.format("%s:%s seq:{%s} begin====>"
+                        , strPlatform
+                        , URI_PATH
+                        , strRunSeq));
+
+        //构建result
+        ResponseRes<String> resResult = new ResponseRes<>();
+        resResult.setRescode(ResponseCode.RESULT_BAD.toStrCode());
+        resResult.setResmsg(ResponseCode.RESULT_BAD.toStrMsg());
+
+        //获取crs信息
+        CommCRSInfo result = CRSUtil.getInfo(code);
+        String resultStr = null;
+        try {
+            if (result != null) resultStr = objectMapper.writeValueAsString(result);
+        } catch (JsonProcessingException e) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                    , String.format("Json序列化异常: error:%s", e));
+        }
+
+        //执行成功
+        if (resultStr != null) {
+            resResult.setRescode(ResponseCode.RESULT_NORMAL.toStrCode());
+            resResult.setResmsg(ResponseCode.RESULT_NORMAL.toStrMsg());
+            resResult.setResdata(resultStr);
+        }
+
+        //end
+        resResult.setTimestamp(System.currentTimeMillis());
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, strUserId
+                , String.format("%s:%s seq:{%s} rescode:{%s} resmsg:{%s} time:{%d ms} end<===="
+                        , strPlatform
+                        , URI_PATH
+                        , strRunSeq
+                        , resResult.getRescode()
+                        , resResult.getResmsg()
+                        , resResult.getTimestamp() - llReqBefore));
+        return resResult;
+    }
+
+    /**
+     * 坐标系转换
+     *
+     * @param request       request
+     * @param strClientType 客户端类型
+     * @param strUserAgent  用户信息
+     * @return crs信息
+     */
+    @PostMapping(value = ApiURI.URI_XXX_CRS_TRANSFORM)
+    public ResponseRes<String> crsTransform(HttpServletRequest request
+            , @RequestHeader(value = ApiURI.HEADER_CLIENT_TYPE, required = false) String strClientType
+            , @RequestHeader(value = ApiURI.HEADER_USER_AGENT, required = false) String strUserAgent
+            , @RequestBody(required = false) @Validated(value = {CommonParamValidSK.class}) GisSurveyCRSParams oJsonParam
+            , BindingResult bindRes) throws SelfException {
+        //入参校验
+        final String URI_PATH = request.getRequestURI();
+        final String strPlatform = CommTool.getPlatformByAgent(strClientType, strUserAgent);
+        final String strUserId = (String) request.getAttribute(TokenAuthenticationService.HEADER_USERID);
+
+        if (oJsonParam == null || bindRes.hasErrors() || oJsonParam.getGeometry() == null) {
+            throw new SelfException(ResponseCode.STATUS_ERROR_JSON_FORMAT.toStrCode()
+                    , String.format(ApiURI.EXCEPTION_FORMAT
+                    , strPlatform
+                    , URI_PATH
+                    , ResponseCode.STATUS_ERROR_JSON_FORMAT.toStrMsg()));
+        }
+
+        //begin
+        long llReqBefore = System.currentTimeMillis();
+        String strRunSeq = String.format("%d-%d", llReqBefore, mSeqCrsGetInfoReq.incrementAndGet());
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, strUserId
+                , String.format("%s:%s seq:{%s} begin====>"
+                        , strPlatform
+                        , URI_PATH
+                        , strRunSeq));
+
+        //构建result
+        ResponseRes<String> resResult = new ResponseRes<>();
+        resResult.setRescode(ResponseCode.RESULT_BAD.toStrCode());
+        resResult.setResmsg(ResponseCode.RESULT_BAD.toStrMsg());
+
+        //转换坐标系
+        Geometry result = CRSUtil.transform(oJsonParam.getGeometry(), oJsonParam.getSourceCRSCode(), oJsonParam.getTargetCRSCode());
+        String resultStr = null;
+        try {
+            if (result != null) {
+                //创建objectMapper,并注册geo序列化
+                ObjectMapper objectMapper = new ObjectMapper();
+                SimpleModule module = new SimpleModule();
+                module.addSerializer(Geometry.class, new GeometrySerializer());
+                objectMapper.registerModule(module);
+
+                resultStr = objectMapper.writeValueAsString(result);
+            }
+        } catch (JsonProcessingException e) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
+                    , String.format("Json序列化异常: error:%s", e));
+        }
+
+        //执行成功
+        if (resultStr != null) {
+            resResult.setRescode(ResponseCode.RESULT_NORMAL.toStrCode());
+            resResult.setResmsg(ResponseCode.RESULT_NORMAL.toStrMsg());
+            resResult.setResdata(resultStr);
+        }
+
+        //end
+        resResult.setTimestamp(System.currentTimeMillis());
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, strUserId
+                , String.format("%s:%s seq:{%s} rescode:{%s} resmsg:{%s} time:{%d ms} end<===="
+                        , strPlatform
+                        , URI_PATH
+                        , strRunSeq
+                        , resResult.getRescode()
+                        , resResult.getResmsg()
+                        , resResult.getTimestamp() - llReqBefore));
+        return resResult;
+    }
 }

+ 3 - 0
src/main/java/com/shkpr/service/alambizplugin/controllerfilter/third/ApiJWTGisSurveyBizFilter.java

@@ -31,6 +31,9 @@ public class ApiJWTGisSurveyBizFilter extends JWTAuthenticationFilter {
         msMapURI2Method.put(String.format("%s/%s", ApiURI.URI_GIS_SURVEY_H, ApiURI.URI_XXX_THIRD_EXPORT_GET), "GET");
         msMapURI2Method.put(String.format("%s/%s", ApiURI.URI_GIS_SURVEY_H, ApiURI.URI_XXX_CAD_CONVERT), "POST");
         msMapURI2Method.put(String.format("%s/%s", ApiURI.URI_GIS_SURVEY_H, ApiURI.URI_XXX_CAD_CONVERT_GET), "GET");
+        msMapURI2Method.put(String.format("%s/%s", ApiURI.URI_GIS_SURVEY_H, ApiURI.URI_XXX_CRS_GET_LIST), "GET");
+        msMapURI2Method.put(String.format("%s/%s", ApiURI.URI_GIS_SURVEY_H, ApiURI.URI_XXX_CRS_GET_INFO), "GET");
+        msMapURI2Method.put(String.format("%s/%s", ApiURI.URI_GIS_SURVEY_H, ApiURI.URI_XXX_CRS_TRANSFORM), "POST");
     }
 
     public ApiJWTGisSurveyBizFilter(String url, AuthenticationManager authenticationManager){

+ 0 - 2
src/main/java/com/shkpr/service/alambizplugin/controllerserializer/GeometrySerializer.java

@@ -22,8 +22,6 @@ public class GeometrySerializer extends JsonSerializer<Geometry> {
      */
     @Override
     public void serialize(Geometry geom, JsonGenerator gen, SerializerProvider serializers) throws IOException {
-        //设置坐标系
-        geom.setSRID(4490);
         //Geom转换为GeoJson
         String geoJson = new GeoJsonWriter().write(geom);
         //读取并输出

+ 7 - 1
src/main/java/com/shkpr/service/alambizplugin/dbdao/pgtype/GeomLineStringTypeHandlePg.java

@@ -11,6 +11,7 @@ import org.locationtech.jts.geom.LineString;
 import org.locationtech.jts.geom.PrecisionModel;
 
 import java.io.IOException;
+import java.math.BigDecimal;
 import java.sql.CallableStatement;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
@@ -67,7 +68,12 @@ public class GeomLineStringTypeHandlePg extends BaseTypeHandler<LineString> {
         if (lineString != null && lineString.getCoordinates() != null && lineString.getCoordinates().length == 2) {
             Coordinate p0 = lineString.getCoordinateN(0);
             Coordinate p1 = lineString.getCoordinateN(1);
-            String value = String.format("[[%s,%s],[%s,%s]]", p0.x, p0.y, p1.x, p1.y);
+            String value = String.format("[[%s,%s],[%s,%s]]",
+                    BigDecimal.valueOf(p0.x).toPlainString(),
+                    BigDecimal.valueOf(p0.y).toPlainString(),
+                    BigDecimal.valueOf(p1.x).toPlainString(),
+                    BigDecimal.valueOf(p1.y).toPlainString()
+            );
             ps.setString(i, value);
         } else {
             //处理空值

+ 5 - 1
src/main/java/com/shkpr/service/alambizplugin/dbdao/pgtype/GeomPointTypeHandlePg.java

@@ -11,6 +11,7 @@ import org.locationtech.jts.geom.Point;
 import org.locationtech.jts.geom.PrecisionModel;
 
 import java.io.IOException;
+import java.math.BigDecimal;
 import java.sql.CallableStatement;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
@@ -63,7 +64,10 @@ public class GeomPointTypeHandlePg extends BaseTypeHandler<Point> {
     public void setNonNullParameter(PreparedStatement ps, int i, Point point, JdbcType jdbcType) throws SQLException {
         if (point != null && point.getCoordinate() != null) {
             //将 Point 序列化化为 [x,y] 字符串
-            String pointStr = String.format("[%f,%f]", point.getX(), point.getY());
+            String pointStr = String.format("[%s,%s]",
+                    BigDecimal.valueOf(point.getX()).toPlainString(),
+                    BigDecimal.valueOf(point.getY()).toPlainString()
+            );
             ps.setString(i, pointStr);
         } else {
             //处理空值

+ 11 - 2
src/main/java/com/shkpr/service/alambizplugin/dbdao/pgtype/GeomTypeHandlePg.java

@@ -12,6 +12,7 @@ import org.locationtech.jts.geom.LineString;
 import org.locationtech.jts.geom.Point;
 
 import java.io.IOException;
+import java.math.BigDecimal;
 import java.sql.CallableStatement;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
@@ -34,7 +35,10 @@ public class GeomTypeHandlePg extends BaseTypeHandler<Geometry> {
             //将 Point 序列化化为 [x,y] 字符串
             Point point = (Point) geometry;
             if (point.getCoordinate() != null) {
-                String pointStr = String.format("[%s,%s]", point.getX(), point.getY());
+                String pointStr = String.format("[%s,%s]",
+                        BigDecimal.valueOf(point.getX()).toPlainString(),
+                        BigDecimal.valueOf(point.getY()).toPlainString()
+                );
                 ps.setString(i, pointStr);
                 return;
             }
@@ -44,7 +48,12 @@ public class GeomTypeHandlePg extends BaseTypeHandler<Geometry> {
             if (lineString.getCoordinates() != null && lineString.getCoordinates().length == 2) {
                 Coordinate p0 = lineString.getCoordinateN(0);
                 Coordinate p1 = lineString.getCoordinateN(1);
-                String value = String.format("[[%s,%s],[%s,%s]]", p0.x, p0.y, p1.x, p1.y);
+                String value = String.format("[[%s,%s],[%s,%s]]",
+                        BigDecimal.valueOf(p0.x).toPlainString(),
+                        BigDecimal.valueOf(p0.y).toPlainString(),
+                        BigDecimal.valueOf(p1.x).toPlainString(),
+                        BigDecimal.valueOf(p1.y).toPlainString()
+                );
                 ps.setString(i, value);
                 return;
             }

+ 36 - 0
src/main/java/com/shkpr/service/alambizplugin/dto/CommCRSBoundingBox.java

@@ -0,0 +1,36 @@
+package com.shkpr.service.alambizplugin.dto;
+
+import lombok.Data;
+
+/**
+ * 通用crs边界框
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+public class CommCRSBoundingBox {
+    /**
+     * The western-most coordinate of the limit of the dataset extent. The value is expressed in longitude in decimal
+     * degrees (positive east).
+     */
+    private double westBoundLongitude;
+
+    /**
+     * The eastern-most coordinate of the limit of the dataset extent. The value is expressed in longitude in decimal
+     * degrees (positive east).
+     */
+    private double eastBoundLongitude;
+
+    /**
+     * The southern-most coordinate of the limit of the dataset extent. The value is expressed in latitude in decimal
+     * degrees (positive north).
+     */
+    private double southBoundLatitude;
+
+    /**
+     * The northern-most, coordinate of the limit of the dataset extent. The value is expressed in latitude in decimal
+     * degrees (positive north).
+     */
+    private double northBoundLatitude;
+}

+ 55 - 0
src/main/java/com/shkpr/service/alambizplugin/dto/CommCRSInfo.java

@@ -0,0 +1,55 @@
+package com.shkpr.service.alambizplugin.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 通用坐标系信息
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+public class CommCRSInfo {
+    /**
+     * 名称
+     */
+    private String name;
+    /**
+     * 编码
+     */
+    private String code;
+    /**
+     * crs纬度
+     */
+    private Integer dimension;
+    /**
+     * 备注
+     */
+    private String remarks;
+    /**
+     * 别名
+     */
+    private List<String> alias;
+    /**
+     * wkt
+     */
+    private String wkt;
+    /**
+     * 范围框
+     */
+    private List<CommCRSBoundingBox> boundingBoxes;
+    /**
+     * 范围描述
+     */
+    private String boundingBoxDescription;
+    /**
+     * 基准名称
+     */
+    private String datumName;
+    /**
+     * 基准编码
+     */
+    private String datumCode;
+}

+ 2 - 2
src/main/resources/application.properties

@@ -150,10 +150,10 @@ async-task.third-import-timeout=PT30M
 async-task.third-export-timeout=PT30M
 async-task.third-export-result-lag=PT1S
 async-task.cad-convert-timeout=PT10M
-async-task.result-path=/home/kprCloud/alam_dma_kpr_plugin/async-results/
+async-task.result-path=./async-results/
 #=============临时文件========================
 temp-file.check-cycle=PT1M
-temp-file.resource-path=/home/kprCloud/alam_dma_kpr_plugin/temp-files/
+temp-file.resource-path=./temp-files/
 temp-file.lifecycle=PT4H