『博客开发日记』之修复天气接口相关的 location 参数传递异常问题

本文最后更新于 2026年6月19日 凌晨

修复天气接口相关的 location 参数传递异常问题


前言

在之前的开发中

对IP地址的解析后传城市名称给天气接口时会把运营商的名称传过去

这就导致了天气接口用不了

本次解决的就是 location 参数传递异常的问题

确保无法识别城市时直接返回接口异常

并提示无法获取该城市的天气信息

因为当前天气接口只能获取国内的天气信息


实现

这里直接给修复后的代码了

IpLocationUtils 中的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
* 从完整的地域信息中提取城市名称
*
* @param region 完整的地域信息,格式:国家|区域|省份|城市|ISP
* @return 城市名称,如果解析失败返回 null
*/
public static String extractCityName(String region) {
if (region == null || region.isBlank()) {
return null;
}

try {
String[] parts = region.split("\\|");
if (parts.length == 0) {
return null;
}

// 常见格式:国家|区域|省份|城市|ISP
// 也可能是:国家|省份|城市|ISP
// 这里按“从右往左优先找城市”的方式,避免把 ISP/运营商当成城市
for (int i = parts.length - 2; i >= 0; i--) {
String candidate = normalizeRegionPart(parts[i]);
if (isValidCityCandidate(candidate)) {
return candidate;
}
}

for (String part : parts) {
String candidate = normalizeRegionPart(part);
if (isValidCityCandidate(candidate)) {
return candidate;
}
}

return null;
} catch (Exception e) {
log.error("提取城市名称失败: region={}, error={}", region, e.getMessage(), e);
return null;
}
}

private static String normalizeRegionPart(String part) {
if (part == null) {
return null;
}
String value = part.trim();
return value.isEmpty() || "0".equals(value) ? null : value;
}

private static boolean isValidCityCandidate(String value) {
if (value == null) {
return false;
}
if (value.contains("电信") || value.contains("联通") || value.contains("移动") || value.contains("铁通")
|| value.contains("广电") || value.contains("未知") || value.contains("保留") || value.contains("ISP")) {
return false;
}
return true;
}

WeatherServiceImpl 中的 getWeatherNow 和 resolveCityName 和 resolveCityNameByIp 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
@Override
public ResponseResult getWeatherNow(String location, String lang, String unit)
{
// 解析并获取城市名称
String cityName = resolveCityName(location);

// 将城市名称转换为 Location_ID
String locationId = CityLocationUtils.getLocationIdByCityName(cityName);
if (!StringUtils.hasText(locationId)) {
log.warn("城市名称无法映射到Location_ID: cityName={}", cityName);
return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(),
"获取天气信息异常:无法获取“ " + cityName + " ”城市的天气信息");
}

// 设置默认参数
lang = StringUtils.hasText(lang) ? lang : "zh";
unit = StringUtils.hasText(unit) ? unit : "m";

// 构建缓存key并尝试从缓存获取
String cacheKey = RedisKeyConstants.WEATHER_NOW_KEY_PREFIX + locationId + ":" + lang + ":" + unit;
WeatherNowVo cachedWeather = redisCache.getCacheObject(cacheKey);
if (cachedWeather != null) {
log.info("从缓存获取天气数据: locationId={}", locationId);
return ResponseResult.okResult(cachedWeather);
}

try {
// 调用和风天气API获取数据
ResponseEntity<QWeatherResponseVo<WeatherNowVo>> response = callWeatherApi(locationId, lang, unit);

// 处理API响应
return handleWeatherResponse(response, cacheKey, locationId);
} catch (Exception e) {
log.error("调用和风天气API异常: locationId={}, cityName={}, error={}", locationId, cityName, e.getMessage(), e);
return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(),
"获取天气信息异常:无法获取“ " + cityName + " ”的天气信息");
}
}

/**
* 根据客户端IP解析城市名称
*
* @return 城市名称
*/
private String resolveCityNameByIp()
{
try {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
String clientIp = IpUtils.getIpAddr(request);
log.info("客户端IP地址: {}", clientIp);

String cityName = IpLocationUtils.getCityNameByIp(clientIp);
if (StringUtils.hasText(cityName)) {
log.info("根据IP解析的城市: {}", cityName);
return cityName;
}

log.warn("IP地址解析城市失败");
} else {
log.warn("无法获取请求上下文");
}
} catch (Exception e) {
log.error("IP地址解析异常: {}", e.getMessage(), e);
}

return null;
}

/**
* 解析并获取城市名称
* 如果location为空,则根据客户端IP自动解析城市
*
* @param location 城市位置(可以是城市名称或Location_ID)
* @return 解析后的城市名称
*/
private String resolveCityName(String location)
{
if (StringUtils.hasText(location)) {
String cityName = location.trim();
log.info("使用传入的城市参数: {}", cityName);
return cityName;
}

return resolveCityNameByIp();
}



PS:该系列只做为作者学习开发项目做的笔记用

不一定符合读者来学习,仅供参考


预告

后续会记录博客的开发过程

每次学习会做一份笔记来进行发表

“一花一世界,一叶一菩提”


版权所有 © 2026 云梦泽
欢迎访问我的个人网站:https://hgt12.github.io/


『博客开发日记』之修复天气接口相关的 location 参数传递异常问题
http://example.com/2026/06/18/『博客开发日记』之修复天气接口相关的 location 参数传递异常问题/
作者
云梦泽
发布于
2026年6月18日
更新于
2026年6月19日
许可协议