From 117d9185f4b1f9f72ca470d41d0fce8f265da719 Mon Sep 17 00:00:00 2001 From: lianlonggang Date: Sun, 14 Dec 2025 18:30:35 +0800 Subject: [PATCH] =?UTF-8?q?=E9=AB=98=E5=BE=B7=E5=9C=B0=E5=9D=80=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../watch/mapper/WatchMonitorDataMapper.java | 1 + .../mapper/xml/WatchMonitorDataMapper.xml | 10 ++ .../service/IWatchMonitorDataService.java | 2 + .../impl/WatchMonitorDataServiceImpl.java | 19 ++++ .../renkang/watch/task/SynWatchGeoJob.java | 58 ++++++++++ .../common/amap/service/AmapService.java | 8 ++ .../amap/service/impl/AmapServiceImpl.java | 106 ++++++++++++++++++ .../jeecg/common/amap/vo/AmapResultVo.java | 30 +++++ .../jeecg/common/amap/vo/RegeoResponse.java | 24 ++++ 9 files changed, 258 insertions(+) create mode 100644 health-watch/health-watch-biz/src/main/java/com/renkang/watch/task/SynWatchGeoJob.java create mode 100644 jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/service/AmapService.java create mode 100644 jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/service/impl/AmapServiceImpl.java create mode 100644 jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/vo/AmapResultVo.java create mode 100644 jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/vo/RegeoResponse.java diff --git a/health-watch/health-watch-biz/src/main/java/com/renkang/watch/mapper/WatchMonitorDataMapper.java b/health-watch/health-watch-biz/src/main/java/com/renkang/watch/mapper/WatchMonitorDataMapper.java index 3a06e66..c7f2693 100644 --- a/health-watch/health-watch-biz/src/main/java/com/renkang/watch/mapper/WatchMonitorDataMapper.java +++ b/health-watch/health-watch-biz/src/main/java/com/renkang/watch/mapper/WatchMonitorDataMapper.java @@ -51,4 +51,5 @@ public interface WatchMonitorDataMapper extends BaseMapper, MP List monitorDayStats(MonitorMonthStatsRequest request); + List getEmptyAddressList(); } diff --git a/health-watch/health-watch-biz/src/main/java/com/renkang/watch/mapper/xml/WatchMonitorDataMapper.xml b/health-watch/health-watch-biz/src/main/java/com/renkang/watch/mapper/xml/WatchMonitorDataMapper.xml index 53b39ac..5b2602c 100644 --- a/health-watch/health-watch-biz/src/main/java/com/renkang/watch/mapper/xml/WatchMonitorDataMapper.xml +++ b/health-watch/health-watch-biz/src/main/java/com/renkang/watch/mapper/xml/WatchMonitorDataMapper.xml @@ -206,4 +206,14 @@ group by data_date order by date; + diff --git a/health-watch/health-watch-biz/src/main/java/com/renkang/watch/service/IWatchMonitorDataService.java b/health-watch/health-watch-biz/src/main/java/com/renkang/watch/service/IWatchMonitorDataService.java index 0dd543c..481af2e 100644 --- a/health-watch/health-watch-biz/src/main/java/com/renkang/watch/service/IWatchMonitorDataService.java +++ b/health-watch/health-watch-biz/src/main/java/com/renkang/watch/service/IWatchMonitorDataService.java @@ -54,4 +54,6 @@ public interface IWatchMonitorDataService extends IService { * @return */ List listCustomForMap(AbnormalEventFilter filter); + + List getEmptyAddressList(); } diff --git a/health-watch/health-watch-biz/src/main/java/com/renkang/watch/service/impl/WatchMonitorDataServiceImpl.java b/health-watch/health-watch-biz/src/main/java/com/renkang/watch/service/impl/WatchMonitorDataServiceImpl.java index 25dbf36..bfe5f94 100644 --- a/health-watch/health-watch-biz/src/main/java/com/renkang/watch/service/impl/WatchMonitorDataServiceImpl.java +++ b/health-watch/health-watch-biz/src/main/java/com/renkang/watch/service/impl/WatchMonitorDataServiceImpl.java @@ -36,6 +36,8 @@ import com.renkang.watch.vo.WatchNotifyVo; import com.renkang.watch.websocket.WebSocket; import lombok.extern.slf4j.Slf4j; import org.jeecg.bean.request.ListUser; +import org.jeecg.common.amap.service.AmapService; +import org.jeecg.common.amap.vo.AmapResultVo; import org.jeecg.common.api.dto.message.BusTemplateMessageDTO; import org.jeecg.common.export.PoiExportHandler; import org.jeecg.common.system.api.ISysBaseAPI; @@ -110,6 +112,8 @@ public class WatchMonitorDataServiceImpl extends ServiceImpl {}", JSONObject.toJSONString(monitorDataEntity)); @@ -962,6 +974,7 @@ public class WatchMonitorDataServiceImpl extends ServiceImpl(); } + public static class Gps { private String id; private double longitude; @@ -1045,4 +1058,10 @@ public class WatchMonitorDataServiceImpl extends ServiceImpl getEmptyAddressList() { + return watchMonitorDataMapper.getEmptyAddressList(); + } + + } diff --git a/health-watch/health-watch-biz/src/main/java/com/renkang/watch/task/SynWatchGeoJob.java b/health-watch/health-watch-biz/src/main/java/com/renkang/watch/task/SynWatchGeoJob.java new file mode 100644 index 0000000..fc7f37f --- /dev/null +++ b/health-watch/health-watch-biz/src/main/java/com/renkang/watch/task/SynWatchGeoJob.java @@ -0,0 +1,58 @@ +package com.renkang.watch.task; + +import com.renkang.watch.entity.WatchMonitorData; +import com.renkang.watch.service.IWatchBindHisService; +import com.renkang.watch.service.IWatchDeviceService; +import com.renkang.watch.service.IWatchMonitorDataService; +import com.renkang.watch.util.WatchDataType; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.jeecg.common.amap.service.AmapService; +import org.jeecg.common.amap.vo.AmapResultVo; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.JobParametersInvalidException; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; +import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; +import org.springframework.batch.core.repository.JobRestartException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@Slf4j +public class SynWatchGeoJob { + + @Autowired + private AmapService amapService; + @Autowired + private IWatchMonitorDataService watchMonitorDataService; + + @XxlJob(value = "sync-watchgeo-data") + public ReturnT syncWatchgeoData(){ + log.info("开始处理高德逆地理编码"); + //先查询地址为空的数据 + List list = watchMonitorDataService.getEmptyAddressList(); + if (!CollectionUtils.isEmpty( list)){ + for (WatchMonitorData watchMonitorData : list) { + AmapResultVo resultVo = amapService.getFormattedAddress(watchMonitorData.getLonGd().doubleValue(), watchMonitorData.getLatGd().doubleValue()); + if (resultVo.isSuccess()) { + watchMonitorData.setAddressGd(resultVo.getAddress()); + watchMonitorData.setAddress(resultVo.getAddress()); + watchMonitorDataService.updateById(watchMonitorData); + }else{ + watchMonitorData.setGpsErrorMsg(resultVo.getErrorMsg()); + watchMonitorDataService.updateById(watchMonitorData); + } + } + } + return ReturnT.SUCCESS; + } + +} diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/service/AmapService.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/service/AmapService.java new file mode 100644 index 0000000..8a76784 --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/service/AmapService.java @@ -0,0 +1,8 @@ +package org.jeecg.common.amap.service; + +import org.jeecg.common.amap.vo.AmapResultVo; + +public interface AmapService { + public AmapResultVo getFormattedAddress(Double lng, Double lat, int timeoutMs); + public AmapResultVo getFormattedAddress(Double lng, Double lat); +} diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/service/impl/AmapServiceImpl.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/service/impl/AmapServiceImpl.java new file mode 100644 index 0000000..330083f --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/service/impl/AmapServiceImpl.java @@ -0,0 +1,106 @@ +package org.jeecg.common.amap.service.impl; + +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.jeecg.common.amap.service.AmapService; +import org.jeecg.common.amap.vo.AmapResultVo; +import org.jeecg.common.amap.vo.RegeoResponse; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.nio.charset.StandardCharsets; + +@Service +@Slf4j +public class AmapServiceImpl implements AmapService { + + @Value("${amap.key}") + private String amapKey; + + @Value("${amap.regeo-url}") + private String regeoUrl; + + // ===== 核心方法 ===== + public AmapResultVo getFormattedAddress(Double lng, Double lat, int timeoutMs) { + AmapResultVo result = validateCoordinates(lng, lat); + if (!result.isSuccess()) { + return result; + } + + int timeout = timeoutMs > 0 ? timeoutMs : 5000; + + RequestConfig config = RequestConfig.custom() + .setConnectTimeout(timeout) + .setSocketTimeout(timeout) + .build(); + + CloseableHttpClient client = HttpClients.custom() + .setDefaultRequestConfig(config) + .build(); + + RestTemplate restTemplate = new RestTemplate( + new HttpComponentsClientHttpRequestFactory(client) + ); + restTemplate.getMessageConverters().forEach(converter -> { + if (converter instanceof org.springframework.http.converter.StringHttpMessageConverter) { + ((org.springframework.http.converter.StringHttpMessageConverter) converter) + .setDefaultCharset(StandardCharsets.UTF_8); + } + }); + + String url = regeoUrl + + "?key=" + amapKey + + "&location=" + lng + "," + lat + + "&extensions=base"; + log.info("高德 API 请求 URL: {}", url); + String json = restTemplate.getForObject(url, String.class); + if (json == null) { + throw new RuntimeException("高德 API 返回空响应"); + } + + RegeoResponse resp = JSON.parseObject(json, RegeoResponse.class); + + if ("1".equals(resp.getStatus())) { + RegeoResponse.Regeocode rg = resp.getRegeocode(); + if (rg != null && rg.getFormattedAddress() != null) { + return AmapResultVo.ok( rg.getFormattedAddress()); + } else { + return AmapResultVo.error("高德地址为空"); + } + } else { + return AmapResultVo.error("高德地址获取异常["+resp.getInfocode()+"]:["+resp.getInfo()+"]"); + } + } + + + // ===== 新增:经纬度校验 ===== + private AmapResultVo validateCoordinates(Double lng, Double lat) { + AmapResultVo result = new AmapResultVo(); + if (lng == null || lat == null) { + return AmapResultVo.error("经纬度不能为空"); + } + if (Double.isNaN(lng) || Double.isInfinite(lng) || + Double.isNaN(lat) || Double.isInfinite(lat)) { + return AmapResultVo.error("经纬度不能为 NaN 或 Infinity"); + } + + if (lng < -180.0 || lng > 180.0) { + return AmapResultVo.error("经度(lng)必须在 [-180.0, 180.0] 范围内"); + } + + if (lat < -90.0 || lat > 90.0) { + return AmapResultVo.error("纬度(lat)必须在 [-90.0, 90.0] 范围内"); + } + return AmapResultVo.ok(); + } + + @Override + public AmapResultVo getFormattedAddress(Double lng, Double lat) { + return getFormattedAddress(lng, lat, 30000); + } +} diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/vo/AmapResultVo.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/vo/AmapResultVo.java new file mode 100644 index 0000000..ee1e5b2 --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/vo/AmapResultVo.java @@ -0,0 +1,30 @@ +package org.jeecg.common.amap.vo; + +import lombok.Data; + +@Data +public class AmapResultVo { + private boolean success = true; + private String errorMsg; + private String address; + + public static AmapResultVo error(String errorMsg) { + AmapResultVo resultVo = new AmapResultVo(); + resultVo.setSuccess(false); + resultVo.setErrorMsg(errorMsg); + return resultVo; + } + + public static AmapResultVo ok(String address) { + AmapResultVo resultVo = new AmapResultVo(); + resultVo.setSuccess(true); + resultVo.setAddress(address); + return resultVo; + } + + public static AmapResultVo ok() { + AmapResultVo resultVo = new AmapResultVo(); + resultVo.setSuccess(true); + return resultVo; + } +} diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/vo/RegeoResponse.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/vo/RegeoResponse.java new file mode 100644 index 0000000..b441d1c --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/amap/vo/RegeoResponse.java @@ -0,0 +1,24 @@ +package org.jeecg.common.amap.vo; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +@Data +public class RegeoResponse { + private String status; + private String info; + private String infocode; + + @JSONField(name = "regeocode") + private Regeocode regeocode; + + @Data + public class Regeocode { + @JSONField(name = "formatted_address") + private String formattedAddress; + + // 后续可扩展 province/city 等 + } + +} +