引言
最近天气变化无常,很多应用都需要集成天气预报功能。作为后端开发者,我们经常需要为移动端、Web端提供天气数据接口。今天就来聊聊如何用SpringBoot整合高德地图API,快速实现一个实用的天气预报服务。
高德地图作为国内领先的地图服务商,提供了丰富的天气API接口,数据准确、更新及时,而且免费额度相当 generous。我们通过SpringBoot来封装这些能力,让天气服务变得更加稳定可靠。
整体架构设计
我们的天气服务架构是这样的:
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ 前端应用层 │───▶│ SpringBoot服务层 │───▶│ 高德天气API │
│ │ │ │ │ │
│ 移动端/PC端 │ │ Controller │ │ 实时天气数据 │
│ 天气查询界面 │ │ Service │ │ 预报天气数据 │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ 缓存层 │
│ │
│ Redis缓存 │
│ 本地缓存 │
└─────────────────┘
│
▼
┌─────────────────┐
│ 配置管理 │
│ │
│ API Key管理 │
│ 城市编码映射 │
└─────────────────┘
核心设计要点
1. API调用策略
高德天气API的特点:
- 实况天气每小时更新多次
- 预报天气每天更新3次(8点、11点、18点)
- 有调用频次限制
- 返回JSON格式数据
所以我们需要合理的缓存策略:
- 实况天气缓存30分钟
- 预报天气缓存2小时
- 失败重试机制
- 降级处理
2. 数据模型设计
天气数据结构化处理:
// 实况天气实体
@Data
public class LiveWeather {
private String province; // 省份
private String city; // 城市
private String adcode; // 城市编码
private String weather; // 天气现象
private String temperature; // 温度
private String windDirection; // 风向
private String windPower; // 风力
private String humidity; // 湿度
private String reportTime; // 发布时间
}
// 预报天气实体
@Data
public class ForecastWeather {
private String city;
private String adcode;
private String province;
private String reportTime;
private List<WeatherCast> casts; // 预报列表
}
@Data
public class WeatherCast {
private String date; // 日期
private String week; // 星期
private String dayWeather; // 白天天气
private String nightWeather; // 夜间天气
private String dayTemp; // 白天温度
private String nightTemp; // 夜间温度
private String dayWind; // 白天风向
private String nightWind; // 夜间风向
private String dayPower; // 白天风力
private String nightPower; // 夜间风力
}
3. 服务层设计
核心服务类设计:
@Service
public class WeatherService {
// 获取实况天气
public LiveWeather getLiveWeather(String cityCode) {
// 1. 先查缓存
// 2. 缓存未命中则调用API
// 3. 更新缓存
// 4. 返回结果
}
// 获取预报天气
public ForecastWeather getForecastWeather(String cityCode) {
// 类似处理逻辑
}
// 城市名称转编码
public String getCityCode(String cityName) {
// 城市名称映射到adcode
}
}
4. 缓存策略实现
@Component
public class WeatherCacheManager {
// 实况天气缓存30分钟
@Cacheable(value = "live_weather", key = "#cityCode")
public LiveWeather getLiveWeatherFromCache(String cityCode) {
return weatherService.getLiveWeatherFromApi(cityCode);
}
// 预报天气缓存2小时
@Cacheable(value = "forecast_weather", key = "#cityCode")
public ForecastWeather getForecastWeatherFromCache(String cityCode) {
return weatherService.getForecastWeatherFromApi(cityCode);
}
}
关键实现细节
1. 高德API调用封装
@Component
public class GaodeWeatherClient {
private final RestTemplate restTemplate;
private final String apiKey;
private final String baseUrl = "https://restapi.amap.com/v3/weather/weatherInfo";
public GaodeWeatherResponse getWeather(String cityCode, String extensions) {
String url = String.format("%s?city=%s&key=%s&extensions=%s",
baseUrl, cityCode, apiKey, extensions);
try {
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
return parseResponse(response.getBody());
} catch (Exception e) {
// 异常处理和降级
return getFallbackWeather(cityCode);
}
}
}
2. 城市编码管理
@Component
public class CityCodeManager {
private Map<String, String> cityCodeMap = new HashMap<>();
@PostConstruct
public void initCityCodes() {
// 初始化常用城市编码
cityCodeMap.put("北京", "110000");
cityCodeMap.put("上海", "310000");
cityCodeMap.put("广州", "440100");
cityCodeMap.put("深圳", "440300");
// ... 更多城市
}
public String getCityCode(String cityName) {
return cityCodeMap.getOrDefault(cityName, "110000"); // 默认北京
}
}
3. 控制器设计
@RestController
@RequestMapping("/api/weather")
public class WeatherController {
@Autowired
private WeatherService weatherService;
// 获取实况天气
@GetMapping("/live/{city}")
public ResponseEntity<LiveWeather> getLiveWeather(@PathVariable String city) {
try {
LiveWeather weather = weatherService.getLiveWeather(city);
return ResponseEntity.ok(weather);
} catch (Exception e) {
return ResponseEntity.status(500).build();
}
}
// 获取预报天气
@GetMapping("/forecast/{city}")
public ResponseEntity<ForecastWeather> getForecastWeather(@PathVariable String city) {
try {
ForecastWeather weather = weatherService.getForecastWeather(city);
return ResponseEntity.ok(weather);
} catch (Exception e) {
return ResponseEntity.status(500).build();
}
}
}
业务场景应用
场景一:移动端天气展示
APP首页需要展示用户所在城市的天气:
- 通过IP定位获取城市
- 调用天气接口获取实况数据
- 展示温度、天气状况、风力等信息
场景二:出行提醒服务
根据天气预报提供出行建议:
- 获取未来3天天气预报
- 分析天气变化趋势
- 给出出行提醒(如带伞、添衣等)
场景三:商户经营分析
帮助商户根据天气调整经营策略:
- 餐饮业根据天气推荐菜品
- 服装业根据温度变化调整库存
- 户外活动根据天气安排时间
最佳实践建议
1. 性能优化
- 合理设置缓存时间
- 批量查询多个城市天气
- 异步更新缓存数据
2. 容错处理
- API调用失败时的降级策略
- 网络异常时的重试机制
- 数据异常时的默认值处理
3. 安全考虑
- API Key的安全存储
- 请求频率限制
- 敏感信息脱敏
4. 监控告警
- API调用成功率监控
- 响应时间监控
- 缓存命中率监控
写在最后
天气预报看似简单,但要做好一个稳定可靠的天气服务并不容易。关键是要理解业务需求,在准确性和实时性之间找到平衡点。
记住几个要点:
- 合理使用缓存,避免频繁调用API
- 做好异常处理,保证服务稳定性
- 监控API使用情况,及时发现问题
- 根据业务场景优化数据结构
通过SpringBoot整合高德地图天气API,我们可以快速搭建一个专业级的天气服务,为各种应用场景提供支撑。
服务端技术精选
作者:技术博主
博客:www.jiangyi.space