diff --git a/fad-app/src/main/java/com/ruoyi/fadapp/controller/FadAppLocationController.java b/fad-app/src/main/java/com/ruoyi/fadapp/controller/FadAppLocationController.java new file mode 100644 index 0000000..efde7d5 --- /dev/null +++ b/fad-app/src/main/java/com/ruoyi/fadapp/controller/FadAppLocationController.java @@ -0,0 +1,34 @@ +package com.ruoyi.fadapp.controller; + +import com.ruoyi.common.core.domain.R; +import com.ruoyi.fadapp.service.IFadAppLocationService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * FAD APP 定位控制器 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/fadapp/location") +public class FadAppLocationController { + + private final IFadAppLocationService locationService; + + /** + * 根据经纬度获取城市 + * + * @param latitude 纬度 + * @param longitude 经度 + * @return 城市名称 + */ + @GetMapping("/city") + public R getCity(@RequestParam Double latitude, @RequestParam Double longitude) { + return R.ok(locationService.getCityByLocation(latitude, longitude)); + } +} diff --git a/fad-app/src/main/java/com/ruoyi/fadapp/controller/FadAppUserController.java b/fad-app/src/main/java/com/ruoyi/fadapp/controller/FadAppUserController.java index 8501442..3426e5b 100644 --- a/fad-app/src/main/java/com/ruoyi/fadapp/controller/FadAppUserController.java +++ b/fad-app/src/main/java/com/ruoyi/fadapp/controller/FadAppUserController.java @@ -11,9 +11,18 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.validation.constraints.NotNull; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * FAD APP用户管理Controller @@ -26,6 +35,7 @@ import javax.validation.constraints.NotNull; @RequestMapping("/fadapp/user") public class FadAppUserController extends BaseController { + private static final String IPSTACK_ACCESS_KEY = ""; private final IFadAppUserService userService; /** @@ -63,4 +73,56 @@ public class FadAppUserController extends BaseController { public R getUserStats() { return R.ok(userService.getUserStats()); } + + /** + * 根据经纬度获取城市 + */ + @GetMapping("/location/city") + public R getCityByLocation(@RequestParam Double latitude, + @RequestParam Double longitude) { + return R.ok(resolveCity(latitude, longitude)); + } + + private String resolveCity(Double latitude, Double longitude) { + if (latitude == null || longitude == null) { + return ""; + } + try { + String urlStr = "https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=" + + URLEncoder.encode(String.valueOf(latitude), StandardCharsets.UTF_8.name()) + + "&lon=" + URLEncoder.encode(String.valueOf(longitude), StandardCharsets.UTF_8.name()) + + "&zoom=10&addressdetails=1"; + HttpURLConnection connection = (HttpURLConnection) new URL(urlStr).openConnection(); + connection.setRequestMethod("GET"); + connection.setConnectTimeout(5000); + connection.setReadTimeout(5000); + connection.setRequestProperty("User-Agent", "FAD-App/1.0"); + + try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { + StringBuilder result = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + result.append(line); + } + return extractCity(result.toString()); + } + } catch (Exception e) { + return ""; + } + } + + private String extractCity(String json) { + if (json == null || json.isEmpty()) { + return ""; + } + String[] keys = new String[]{"city", "town", "village", "county", "state"}; + for (String key : keys) { + Pattern pattern = Pattern.compile("\\\"" + key + "\\\"\\s*:\\s*\\\"([^\\\"]+)\\\""); + Matcher matcher = pattern.matcher(json); + if (matcher.find()) { + return matcher.group(1); + } + } + return ""; + } } \ No newline at end of file diff --git a/fad-app/src/main/java/com/ruoyi/fadapp/service/IFadAppLocationService.java b/fad-app/src/main/java/com/ruoyi/fadapp/service/IFadAppLocationService.java new file mode 100644 index 0000000..93fec4f --- /dev/null +++ b/fad-app/src/main/java/com/ruoyi/fadapp/service/IFadAppLocationService.java @@ -0,0 +1,16 @@ +package com.ruoyi.fadapp.service; + +/** + * FAD APP 定位服务接口 + */ +public interface IFadAppLocationService { + + /** + * 根据经纬度获取城市 + * + * @param latitude 纬度 + * @param longitude 经度 + * @return 城市名称 + */ + String getCityByLocation(Double latitude, Double longitude); +} diff --git a/fad-app/src/main/java/com/ruoyi/fadapp/service/impl/FadAppLocationServiceImpl.java b/fad-app/src/main/java/com/ruoyi/fadapp/service/impl/FadAppLocationServiceImpl.java new file mode 100644 index 0000000..78a0e3e --- /dev/null +++ b/fad-app/src/main/java/com/ruoyi/fadapp/service/impl/FadAppLocationServiceImpl.java @@ -0,0 +1,87 @@ +package com.ruoyi.fadapp.service.impl; + +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.fadapp.service.IFadAppLocationService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * FAD APP 定位服务实现 + */ +@Slf4j +@Service +public class FadAppLocationServiceImpl implements IFadAppLocationService { + + private static final String AMAP_REVERSE_URL = "https://restapi.amap.com/v3/geocode/regeo"; + + private final RestTemplate restTemplate = new RestTemplate(); + + @Value("${fad.amap.key:}") + private String amapKey; + + @Override + public String getCityByLocation(Double latitude, Double longitude) { + if (latitude == null || longitude == null) { + return ""; + } + + if (!org.springframework.util.StringUtils.hasText(amapKey)) { + log.warn("高德地图 key 未配置"); + return ""; + } + + try { + Map params = new LinkedHashMap<>(); + params.put("key", amapKey); + params.put("location", longitude + "," + latitude); + params.put("extensions", "base"); + params.put("batch", "false"); + params.put("roadlevel", 0); + params.put("output", "JSON"); + + StringBuilder url = new StringBuilder(AMAP_REVERSE_URL).append("?"); + params.forEach((key, value) -> url.append(key).append("=").append(value).append("&")); + url.setLength(url.length() - 1); + + JSONObject response = restTemplate.getForObject(url.toString(), JSONObject.class); + if (response == null) { + return ""; + } + + if (!"1".equals(response.getString("status"))) { + log.warn("高德逆地理编码失败: {}", response); + return ""; + } + + JSONObject regeocode = response.getJSONObject("regeocode"); + if (regeocode == null) { + return ""; + } + + JSONObject addressComponent = regeocode.getJSONObject("addressComponent"); + if (addressComponent == null) { + return ""; + } + + String city = addressComponent.getString("city"); + if (org.springframework.util.StringUtils.hasText(city)) { + return city; + } + + String province = addressComponent.getString("province"); + if (org.springframework.util.StringUtils.hasText(province)) { + return province; + } + + return ""; + } catch (Exception e) { + log.warn("根据经纬度获取城市失败, latitude={}, longitude={}, err={}", latitude, longitude, e.getMessage()); + return ""; + } + } +} diff --git a/fad-app/src/main/resources/application.yml b/fad-app/src/main/resources/application.yml new file mode 100644 index 0000000..cf1304f --- /dev/null +++ b/fad-app/src/main/resources/application.yml @@ -0,0 +1,3 @@ +fad: + amap: + key: 978ae5bc551f57d172d3e397af5a6f67 diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index eb429c1..a62f541 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -317,3 +317,8 @@ flowable: check-process-definitions: false # 关闭历史任务定时任务job async-history-executor-activate: false + + +fad: + amap: + key: 978ae5bc551f57d172d3e397af5a6f67 \ No newline at end of file