20260329:1、规范地图,系统已经融入高德、百度正逆地址编码;2、Modbus设备经纬度用LBS指令读取

This commit is contained in:
George 2026-03-29 09:31:27 +08:00
parent 775fa83e25
commit bcc78fe240
18 changed files with 478 additions and 48 deletions

View File

@ -2,16 +2,18 @@ package com.fastbee.web.controller.backend;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.utils.StringUtils;
import com.fastbee.http.map.ILocationService;
import com.fastbee.http.map.LocationServiceFactory;
import com.fastbee.http.model.AddressInfo;
import com.fastbee.http.model.Coordinate;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.concurrent.TimeUnit;
/**
@ -28,6 +30,9 @@ public class BackendController {
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private LocationServiceFactory locationServiceFactory;
@ApiOperation("设置缓存值(调试/运维)")
@PreAuthorize("@ss.hasPermi('monitor:cache:remove')")
@PostMapping("/set")
@ -64,4 +69,40 @@ public class BackendController {
redisTemplate.delete(key);
return AjaxResult.success("ok");
}
// getAddressByCoordinate
@ApiOperation("根据坐标获取地址(逆地理编码)")
@PreAuthorize("@ss.hasPermi('monitor:cache:remove')")
@GetMapping("/getAddressByCoordinate")
public AjaxResult getAddressByCoordinate(@RequestParam("coordinate") String coordinate, @RequestParam("provider") String provider) {
if (StringUtils.isEmpty(coordinate)) {
return AjaxResult.error("coordinate不能为空");
}
String[] split = coordinate.split(",");
// 工厂模式获取定位服务
ILocationService service = locationServiceFactory.getLocationService(provider);
Coordinate c = new Coordinate(BigDecimal.valueOf(Double.parseDouble(split[0])), BigDecimal.valueOf(Double.parseDouble(split[1])));
AddressInfo addressByCoordinate = service.getAddressByCoordinate(c);
// TODO:用地图服务根据坐标获取地址
return AjaxResult.success(addressByCoordinate);
}
// getCoordinateByAddress
@ApiOperation("根据地址获取坐标(正地理编码)")
@PreAuthorize("@ss.hasPermi('monitor:cache:remove')")
@GetMapping("/getCoordinateByAddress")
public AjaxResult getCoordinateByAddress(@RequestParam("address") String address, @RequestParam("provider") String provider) {
if (StringUtils.isEmpty(address)) {
return AjaxResult.error("address不能为空");
}
// TODO:用地图服务根据地址获取坐标
ILocationService service = locationServiceFactory.getLocationService(provider);
Coordinate coordinateByAddress = service.getCoordinateByAddress(address);
return AjaxResult.success(coordinateByAddress);
}
}

View File

@ -154,7 +154,3 @@ logging:
swagger:
enabled: true # 是否开启swagger
pathMapping: /dev-api # 请求前缀
# 地图配置
map:
provider: baidu

View File

@ -153,7 +153,3 @@ logging:
swagger:
enabled: true # 是否开启swagger
pathMapping: /prod-api # 请求前缀
# 地图配置
map:
provider: baidu

View File

@ -103,7 +103,3 @@ logging:
swagger:
enabled: true # 是否开启swagger
pathMapping: /test-api # 请求前缀
# 地图配置
map:
provider: baidu

View File

@ -217,5 +217,11 @@ liteflow:
scriptTypeField: script_type
scriptLanguageField: script_language
scriptEnableField: enable
other:
# 地图配置
map:
provider: gaode # 提供者
baidu_ak: 0SD4KrYeMXVu8Ox2pxQGDOw3NmDYiKIw
gaode_ak: 3af85be39e2f28334097781349336157
gaode_secret: d0561ad20142e74f8c59edc5deafdbe4

View File

@ -371,14 +371,17 @@ public interface FastBeeConstant {
String GB28181 = "GB28181";
}
// 地图相关
/**
* 第三方地图 Web 服务:仅存放根地址与各接口路径,完整 URL = BASE + PATH。
*/
interface MAP {
// 百度 BAIDU
String BAIDU_GEOCODING = "http://api.map.baidu.com/geocoding/v3/";
// 百度(https://lbs.baidu.com/faq/api?title=webapi/guide/webservice-geocoding)
String BAIDU_BASE = "https://api.map.baidu.com";
// 高德 GAODE
// 高德(https://lbs.amap.com/api/webservice/guide/api/georegeo)
String GAODE_BASE = "https://restapi.amap.com";
// 腾讯 TENCENT
// 腾讯 TENCENT(预留)
}
}

View File

@ -136,10 +136,10 @@ public class ATCommandParserUtils {
if (lbsValue != null && lbsValue.contains(",")) {
String[] parts = lbsValue.split(",");
try {
// 注意:实际顺序可能是 [纬度,经度] 或 [经度,纬度],根据文档通常为经度,纬度
// 返回 [经度,纬度]
double latitude = Double.parseDouble(parts[0]);
double longitude = Double.parseDouble(parts[1]);
return new double[]{latitude, longitude};
return new double[]{longitude, latitude};
} catch (NumberFormatException e) {
return null;
}
@ -292,7 +292,7 @@ public class ATCommandParserUtils {
System.out.println("LBS解析结果: " + parseLBSString(lbsHex));
double[] lbs = parseLBS(lbsHex);
if (lbs != null) {
System.out.println("纬度: " + lbs[0] + ", 经度: " + lbs[1]);
System.out.println("经度: " + lbs[0] + ", 纬度: " + lbs[1]);
}
// 测试通用解析

View File

@ -33,6 +33,7 @@ import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
@ -312,7 +313,7 @@ public class DeviceDebugLogAspect {
return;
}
// 跟新IMEI、ICCID
// 更新IMEI、ICCID、longitude、latitude
if (StringUtils.isEmpty(device.getImei()) || StringUtils.isEmpty(device.getIccid())) {
Map<String, String> atCommandMap = ATCommandParserUtils.parseATResponseFromHex(context.sourceData);
Device updateDevice = new Device();
@ -322,6 +323,16 @@ public class DeviceDebugLogAspect {
if (StringUtils.isEmpty(device.getIccid())) {
updateDevice.setIccid(atCommandMap.get("ICCID"));
}
if (device.getLongitude() == null && device.getLatitude() == null) {
String lbsValue = atCommandMap.get("LBS");
if (lbsValue != null) {
String[] lbsArray = lbsValue.split(",");
if (lbsArray.length == 2) {
updateDevice.setLongitude(new BigDecimal(lbsArray[1]));
updateDevice.setLatitude(new BigDecimal(lbsArray[0]));
}
}
}
updateDevice.setDeviceId(device.getDeviceId());
updateDevice.setUpdateBy("DTU");
updateDevice.setUpdateTime(DateUtils.getNowDate());

View File

@ -118,6 +118,11 @@ public class PowerOnTriggerTaskExecutor {
deviceMessage.setMessage("41542b49434349445c725c6e");
deviceMessageService.messagePost(deviceMessage);
}
if (device.getLongitude() == null || device.getLatitude() == null) {
deviceMessage.setMessage("41542b4c42535c725c6e"); // AT+LBS\r\n
deviceMessageService.messagePost(deviceMessage);
}
}
/**

View File

@ -29,7 +29,7 @@ public class ThingsModelPushJob {
/**
* 每分钟执行一次,检查并触发到期的推送任务
*/
@Scheduled(fixedDelay = 60_000)
@Scheduled(fixedDelay = 300_000)
public void execute() {
List<ThingsModelPushConfig> configs = pushConfigService.selectAllEnabled();
if (CollectionUtils.isEmpty(configs)) {

View File

@ -1,8 +1,4 @@
package com.fastbee.http.ip;/**
* @description: IP地址相关客户端调用
* @author Sumuxi
* @date 2026/3/8
*/
package com.fastbee.http.ip;
import com.alibaba.fastjson2.JSONObject;
import com.fastbee.common.constant.Constants;

View File

@ -5,6 +5,7 @@ import com.fastbee.common.constant.Constants;
import com.fastbee.common.constant.ErrorCodeConstants;
import com.fastbee.common.constant.FastBeeConstant;
import com.fastbee.common.utils.http.HttpUtils;
import com.fastbee.http.model.AddressInfo;
import com.fastbee.http.model.Coordinate;
import com.fastbee.http.utils.CoordinateTransformUtils;
import lombok.extern.slf4j.Slf4j;
@ -16,6 +17,7 @@ import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.Objects;
import static com.fastbee.common.exception.ServiceExceptionUtil.exception;
@ -30,9 +32,15 @@ import static com.fastbee.common.exception.ServiceExceptionUtil.exception;
@Service("baiduLocationService")
public class BaiduILocationService implements ILocationService {
@Value("${other.baidu_ak}")
@Value("${map.baidu_ak}")
private String baiduAK;
// 地理编码
private static final String BAIDU_PATH_GEOCODING = "/geocoding/v3/";
// 逆地理编码
private static final String BAIDU_PATH_REVERSE_GEOCODING = "/reverse_geocoding/v3/";
/**
* 根据结构化地址获取地理编码(即经纬度)
* 地理编码服务提供将结构化地址数据(如:北京市海淀区上地十街十号)转换为对应坐标点(经纬度)功能。
@ -43,7 +51,7 @@ public class BaiduILocationService implements ILocationService {
public Coordinate getCoordinateByAddress(String address) {
log.info("结构化地址:{}", address);
String baseUrl = FastBeeConstant.MAP.BAIDU_GEOCODING;
String baseUrl = FastBeeConstant.MAP.BAIDU_BASE + BAIDU_PATH_GEOCODING;
address = StringUtils.isEmpty(address) || Objects.equals("内网IP", address) ? "湖南省长沙市岳麓区" : address;
String encodedAddress;
try {
@ -61,6 +69,55 @@ public class BaiduILocationService implements ILocationService {
return null;
}
/**
* 逆地理编码:坐标系为 BD09,与百度地理编码返回及本类 {@link #convertPlatformCoordinateFromWgs84} 一致。
* 文档:https://lbs.baidu.com/faq/api?title=webapi/guide/webservice-geocoding
*/
@Override
public AddressInfo getAddressByCoordinate(Coordinate coordinate) {
if (coordinate == null || coordinate.getLongitude() == null || coordinate.getLatitude() == null) {
log.warn("百度逆地理编码:坐标为空");
return null;
}
if (StringUtils.isBlank(baiduAK)) {
log.warn("百度逆地理编码:未配置 map.baidu_ak");
return null;
}
double lat = coordinate.getLatitude().doubleValue();
double lng = coordinate.getLongitude().doubleValue();
// location:纬度,经度;coordtype 与坐标系一致
String location = String.format(Locale.US, "%.6f,%.6f", lat, lng);
String param = "ak=" + baiduAK + "&output=json&coordtype=bd09ll&location=" + location;
String response = HttpUtils.sendGet(FastBeeConstant.MAP.BAIDU_BASE + BAIDU_PATH_REVERSE_GEOCODING, param, Constants.UTF8);
if (StringUtils.isEmpty(response)) {
return null;
}
JSONObject root = JSONObject.parseObject(response);
if (root == null || root.getIntValue("status") != 0) {
log.warn("百度逆地理编码失败 status={} message={}", root != null ? root.get("status") : null,
root != null ? root.getString("message") : null);
return null;
}
JSONObject result = root.getJSONObject("result");
if (result == null) {
return null;
}
AddressInfo info = new AddressInfo();
info.setFormattedAddress(result.getString("formatted_address"));
JSONObject ac = result.getJSONObject("addressComponent");
if (ac != null) {
info.setCountry(ac.getString("country"));
info.setProvince(ac.getString("province"));
info.setCity(ac.getString("city"));
info.setDistrict(ac.getString("district"));
info.setTown(ac.getString("town"));
info.setStreet(ac.getString("street"));
info.setStreetNumber(ac.getString("street_number"));
}
info.setBuilding(result.getString("business"));
return info;
}
@Override
public Coordinate convertToWgs84(Coordinate baiduCoordinate) {
@ -71,4 +128,13 @@ public class BaiduILocationService implements ILocationService {
return new Coordinate(BigDecimal.valueOf(doubles[0]), BigDecimal.valueOf(doubles[1]));
}
@Override
public Coordinate convertPlatformCoordinateFromWgs84(Coordinate wgs84Coordinate) {
//世界坐标系(WGS84)的坐标转换为百度坐标系(BD09)
double[] doubles = CoordinateTransformUtils.wgs84ToBd09(wgs84Coordinate.getLongitude().doubleValue(),
wgs84Coordinate.getLatitude().doubleValue());
return new Coordinate(BigDecimal.valueOf(doubles[0]), BigDecimal.valueOf(doubles[1]));
}
}

View File

@ -1,10 +1,27 @@
package com.fastbee.http.map;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.fastbee.common.constant.Constants;
import com.fastbee.common.constant.FastBeeConstant;
import com.fastbee.common.utils.http.HttpUtils;
import com.fastbee.common.utils.sign.Md5Utils;
import com.fastbee.http.model.AddressInfo;
import com.fastbee.http.model.Coordinate;
import com.fastbee.http.utils.CoordinateTransformUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
/**
* @description: 高德地图API实现类
@ -12,15 +29,205 @@ import java.math.BigDecimal;
* @author Sumuxi
* @date 2026/3/8
*/
@Slf4j
@Service("gaodeLocationService")
public class GaodeLocationService implements ILocationService {
@Value("${map.gaode_ak:3af85be39e2f28334097781349336157}")
private String gaodeAK;
/**
* 数字签名私钥(控制台开启「数字签名」后必填)。
* 算法参见:https://lbs.amap.com/faq/quota-key/key/41181
*/
@Value("${map.gaode_secret:d0561ad20142e74f8c59edc5deafdbe4}")
private String gaodeSecret;
/** 地理编码:地址 → 经纬度(GCJ-02) */
private static final String GAODE_PATH_GEO = "/v3/geocode/geo";
/** 逆地理编码:经纬度 → 地址 */
private static final String GAODE_PATH_REGEO = "/v3/geocode/regeo";
/**
* 地理编码:结构化地址转经纬度,坐标系为 GCJ-02(火星坐标),与高德 Web 服务一致。
* 文档:https://lbs.amap.com/api/webservice/guide/api/georegeo
* 数字签名:MD5 使用 UTF-8 下原始参数值拼接(与控制台一致),请求中的 address 需单独 URL 编码,参见
* https://lbs.amap.com/faq/quota-key/key/41181
*/
@Override
public Coordinate getCoordinateByAddress(String address) {
return null;
if (StringUtils.isBlank(address)) {
log.warn("高德地理编码:地址为空");
return null;
}
if (StringUtils.isBlank(gaodeAK)) {
log.warn("高德地理编码:未配置 map.gaode_ak");
return null;
}
String raw = address.trim();
TreeMap<String, String> forSign = new TreeMap<>();
forSign.put("address", raw);
forSign.put("output", "json");
forSign.put("key", gaodeAK);
String sig = null;
if (StringUtils.isNotBlank(gaodeSecret)) {
sig = Md5Utils.hash(joinKeyValueSorted(forSign) + gaodeSecret);
}
String encodedAddress;
try {
encodedAddress = URLEncoder.encode(raw, StandardCharsets.UTF_8.toString());
} catch (UnsupportedEncodingException e) {
log.error("高德地理编码:地址 UTF-8 编码失败", e);
return null;
}
StringBuilder qb = new StringBuilder();
qb.append("address=").append(encodedAddress);
qb.append("&key=").append(gaodeAK);
qb.append("&output=json");
if (sig != null) {
qb.append("&sig=").append(sig);
}
String response = HttpUtils.sendGet(FastBeeConstant.MAP.GAODE_BASE + GAODE_PATH_GEO, qb.toString(), Constants.UTF8);
if (StringUtils.isBlank(response)) {
return null;
}
JSONObject root = JSONObject.parseObject(response);
if (root == null || !"1".equals(String.valueOf(root.get("status")))) {
log.warn("高德地理编码失败 status={} info={}", root != null ? root.get("status") : null,
root != null ? root.getString("info") : null);
return null;
}
JSONArray geocodes = root.getJSONArray("geocodes");
if (geocodes == null || geocodes.isEmpty()) {
return null;
}
JSONObject first = geocodes.getJSONObject(0);
if (first == null) {
return null;
}
String location = first.getString("location");
if (StringUtils.isBlank(location)) {
return null;
}
String[] parts = location.split(",");
if (parts.length != 2) {
return null;
}
try {
BigDecimal lng = new BigDecimal(parts[0].trim());
BigDecimal lat = new BigDecimal(parts[1].trim());
return new Coordinate(lng, lat);
} catch (NumberFormatException e) {
log.warn("高德地理编码:无法解析坐标 location={}", location);
return null;
}
}
/**
* 逆地理编码:坐标系为 GCJ-02(火星坐标),与高德 Web 服务一致。
* 文档:https://lbs.amap.com/api/webservice/guide/api/georegeo
*/
@Override
public AddressInfo getAddressByCoordinate(Coordinate coordinate) {
if (coordinate == null || coordinate.getLongitude() == null || coordinate.getLatitude() == null) {
log.warn("高德逆地理编码:坐标为空");
return null;
}
if (StringUtils.isBlank(gaodeAK)) {
log.warn("高德逆地理编码:未配置 map.gaode_key");
return null;
}
double lng = coordinate.getLongitude().doubleValue();
double lat = coordinate.getLatitude().doubleValue();
// 经度在前、纬度在后,小数点后不超过 6 位
String location = String.format(Locale.US, "%.6f,%.6f", lng, lat);
Map<String, String> regeoParams = new HashMap<>(4);
regeoParams.put("extensions", "base");
regeoParams.put("location", location);
regeoParams.put("output", "json");
String param = buildGaodeWebServiceQuery(regeoParams);
String response = HttpUtils.sendGet(FastBeeConstant.MAP.GAODE_BASE + GAODE_PATH_REGEO, param, Constants.UTF8);
if (StringUtils.isBlank(response)) {
return null;
}
JSONObject root = JSONObject.parseObject(response);
if (root == null || !"1".equals(String.valueOf(root.get("status")))) {
log.warn("高德逆地理编码失败 status={} info={}", root != null ? root.get("status") : null,
root != null ? root.getString("info") : null);
return null;
}
JSONObject regeocode = root.getJSONObject("regeocode");
if (regeocode == null) {
return null;
}
AddressInfo info = new AddressInfo();
info.setFormattedAddress(regeocode.getString("formatted_address"));
JSONObject ac = regeocode.getJSONObject("addressComponent");
if (ac != null) {
info.setCountry(ac.getString("country"));
info.setProvince(ac.getString("province"));
info.setCity(parseGaodeCity(ac));
info.setDistrict(ac.getString("district"));
info.setTown(ac.getString("township"));
JSONObject streetNumber = ac.getJSONObject("streetNumber");
if (streetNumber != null) {
info.setStreet(streetNumber.getString("street"));
info.setStreetNumber(streetNumber.getString("number"));
}
JSONObject building = ac.getJSONObject("building");
if (building != null) {
info.setBuilding(building.getString("name"));
}
}
return info;
}
/**
* 直辖市等场景下 city 可能为空数组,需回退到省名等。
*/
private static String parseGaodeCity(JSONObject ac) {
Object cityVal = ac.get("city");
if (cityVal instanceof String) {
String s = (String) cityVal;
if (StringUtils.isNotBlank(s)) {
return s;
}
} else if (cityVal instanceof JSONArray) {
JSONArray arr = (JSONArray) cityVal;
if (!arr.isEmpty()) {
return arr.getString(0);
}
}
String province = ac.getString("province");
return StringUtils.isNotBlank(province) ? province : null;
}
/**
* 组装高德 Web 服务 GET 查询串:参数名升序拼接后接私钥做 MD5 得到 sig(与官方数字签名说明一致)。
* 未配置 {@code map.gaode_secret} 时不传 sig,适用于未开启数字签名的 Key。
*/
private String buildGaodeWebServiceQuery(Map<String, String> paramsWithoutKey) {
TreeMap<String, String> sorted = new TreeMap<>(paramsWithoutKey);
sorted.put("key", gaodeAK);
if (StringUtils.isNotBlank(gaodeSecret)) {
String signSource = joinKeyValueSorted(sorted) + gaodeSecret;
sorted.put("sig", Md5Utils.hash(signSource));
}
return joinKeyValueSorted(sorted);
}
private static String joinKeyValueSorted(TreeMap<String, String> sorted) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> e : sorted.entrySet()) {
if (sb.length() > 0) {
sb.append('&');
}
sb.append(e.getKey()).append('=').append(e.getValue());
}
return sb.toString();
}
@Override
@ -33,4 +240,14 @@ public class GaodeLocationService implements ILocationService {
return new Coordinate(BigDecimal.valueOf(doubles[0]), BigDecimal.valueOf(doubles[1]));
}
@Override
public Coordinate convertPlatformCoordinateFromWgs84(Coordinate wgs84Coordinate) {
// 将世界坐标 转化为 高德(火星)坐标
double[] doubles = CoordinateTransformUtils.wgs84ToGcj02(
wgs84Coordinate.getLongitude().doubleValue(),
wgs84Coordinate.getLatitude().doubleValue()
);
return new Coordinate(BigDecimal.valueOf(doubles[0]), BigDecimal.valueOf(doubles[1]));
}
}

View File

@ -1,5 +1,6 @@
package com.fastbee.http.map;
import com.fastbee.http.model.AddressInfo;
import com.fastbee.http.model.Coordinate;
/**
@ -18,11 +19,13 @@ public interface ILocationService {
Coordinate getCoordinateByAddress(String address);
/**
* 根据经纬度获取详细地址
* @param coordinate 经纬度
* @return 详细地址信息
* 根据经纬度逆地理编码获取结构化地址。
* 坐标系因实现而异:{@code gaodeLocationService} 使用 GCJ-02;{@code baiduLocationService} 使用 BD09。
*
* @param coordinate 经纬度(经度、纬度)
* @return 详细地址信息;参数无效、配置缺失或第三方失败时可能为 {@code null}
*/
//AddressInfo getAddressByCoordinate(Coordinate coordinate);
AddressInfo getAddressByCoordinate(Coordinate coordinate);
/**
@ -31,4 +34,12 @@ public interface ILocationService {
* @return 世界坐标系
*/
Coordinate convertToWgs84(Coordinate coordinate);
/**
* 将世界坐标系(WGS84)的坐标转换为指定平台(高德、百度、腾讯)坐标系。
* @param wgs84Coordinate WGS84 坐标
* @return 转换后的目标坐标系坐标
*/
Coordinate convertPlatformCoordinateFromWgs84(Coordinate wgs84Coordinate);
}

View File

@ -26,14 +26,23 @@ public class LocationServiceFactory {
/**
* 获取当前配置的 LocationService 实例
* @param providerArr 指定地图提供者,优先级高于配置文件
* @return 具体服务实现
*/
public ILocationService getLocationService() {
// if ("gaode".equalsIgnoreCase(provider)) {
// return gaodeLocationService;
// } else if ("tencent".equalsIgnoreCase(provider)) {
// return tencentLocationService;
// }
public ILocationService getLocationService(String... providerArr) {
String provider;
// 优先参数指定服务商
if (providerArr != null && providerArr.length > 0){
provider = providerArr[0];
} else {
provider = this.provider;
}
if ("gaode".equalsIgnoreCase(provider)) {
return gaodeLocationService;
} /*else if ("tencent".equalsIgnoreCase(provider)) {
return tencentLocationService;
}*/
// 默认返回百度
return baiduLocationService;
}

View File

@ -0,0 +1,59 @@
package com.fastbee.http.model;
import lombok.Data;
/**
* @description: 地址信息
* 国家、省份、城市、区县、城镇、乡村、街道、门牌号码、屋邨、大厦
*
* @author Sumuxi
* @date 2026/3/28
*/
@Data
public class AddressInfo {
/**
* 格式化地址
*/
private String formattedAddress;
/**
* 国家
*/
private String country;
/**
* 省份
*/
private String province;
/**
* 城市
*/
private String city;
/**
* 区/县
*/
private String district;
/**
* 乡/镇
*/
private String town;
/**
* 街道
*/
private String street;
/**
* 门牌号
*/
private String streetNumber;
/**
* 建筑/楼栋
*/
private String building;
}

View File

@ -181,7 +181,7 @@ public class Device extends BaseEntity {
/**
* 是否自定义位置
**/
@ApiModelProperty("定位方式(1=ip自动定位,2=设备定位,3=自定义)")
@ApiModelProperty("定位方式(1=自动定位[ip地址、modbus LBS],2=设备定位,3=自定义)")
private Integer locationWay;
/**

View File

@ -27,6 +27,7 @@ import com.fastbee.common.utils.json.JsonUtils;
import com.fastbee.http.ip.IPAddressService;
import com.fastbee.http.map.ILocationService;
import com.fastbee.http.map.LocationServiceFactory;
import com.fastbee.http.model.AddressInfo;
import com.fastbee.http.model.Coordinate;
import com.fastbee.iot.cache.IDeviceCache;
import com.fastbee.iot.cache.ITSLCache;
@ -1099,6 +1100,7 @@ public class DeviceServiceImpl implements IDeviceService {
// 随机经纬度和地址
//SysUser user = getLoginUser().getUser();
device.setNetworkIp(sysUser.getLoginIp());
device.setTransport(product.getTransport()); // 便于Modbus设备LBS定位
setLocation(sysUser.getLoginIp(), device);
deviceMapper.insertDevice(device);
// 处理modbus产品
@ -1632,13 +1634,29 @@ public class DeviceServiceImpl implements IDeviceService {
* @param device 设备信息
*/
private void setLocation(String ip, Device device) {
// 工厂模式获取定位服务
ILocationService service = locationServiceFactory.getLocationService();
// Modbus设备采用LBS定位(从设备获取经纬度)
if (Objects.equals(1, device.getLocationWay()) && FastBeeConstant.PROTOCOL.ModbusRtu.equals(device.getTransport())) {
log.info("Modbus设备采用LBS定位{}", device.getSerialNumber());
// 将经纬度转换为地址编码 networkAddress
if (StringUtils.isEmpty(device.getNetworkAddress()) && device.getLongitude() != null && device.getLatitude() != null) {
Coordinate platformCoordinate = service.convertPlatformCoordinateFromWgs84(new Coordinate(device.getLongitude(), device.getLatitude()));
AddressInfo addressInfo = service.getAddressByCoordinate(platformCoordinate);
String networkAddress = StringUtils.isEmpty(addressInfo.getBuilding()) ? addressInfo.getFormattedAddress() : addressInfo.getBuilding();
device.setNetworkAddress(networkAddress);
log.info("{}- 设置地址:{}", device.getSerialNumber(), networkAddress);
}
return;
}
try {
// 根据IP获取地址
String address = ipAddressService.getAddressByIP(ip);
device.setNetworkAddress(address);
log.info("{}- 设置地址:{}", device.getSerialNumber(), address);
// 查询经纬度
ILocationService service = locationServiceFactory.getLocationService();
Coordinate coordinate = service.getCoordinateByAddress(address);
Coordinate wgs84Coordinate = service.convertToWgs84(coordinate);
device.setLongitude(wgs84Coordinate.getLongitude());