实现异步天气数据获取与Spring缓存集成

你好呀,我是小邹。

在Web应用中,实时天气数据的获取是一个常见的需求,特别是在需要频繁更新天气信息的场景下,如旅游网站、天气应用或任何需要展示地理位置相关天气的应用。然而,频繁的外部API调用不仅会增加服务器的负担,还可能导致网络延迟,影响用户体验。为了优化这一过程,本文将介绍如何在Spring Boot应用中利用异步调用和缓存技术来高效地获取并存储天气数据。

效果图

引入Spring异步支持

在Spring框架中,可以使用@Async注解来指定方法应该异步执行。这允许应用在等待耗时操作(如网络调用)完成的同时继续处理其他请求,从而提高了整体的响应性和吞吐量。

利用Spring Cache缓存结果

为了减少对远程API的重复调用,我们可以使用Spring Cache框架来缓存天气数据。@Cacheable注解可以自动存储方法的返回值,如果下次请求相同的数据,它将从缓存中读取,而不是重新执行方法。

代码实现

以下代码示例展示了如何在Spring Boot中结合使用@Async@Cacheable注解来异步获取并缓存天气数据:

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.ui.Model;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.data.util.Pair;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.collection.CollUtil;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.time.LocalDateTime;

@Service
public class WeatherService {

    private static final String WEATHER_CACHE_NAME = "weatherCache";
    private static final String GAO_DE_KEY = "YOUR_GAODE_API_KEY";
    private final RestTemplate restTemplate;

    @Autowired
    public WeatherService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @Async
    @Cacheable(value = WEATHER_CACHE_NAME, key = "'todayWeather'")
    public void getWeather(Model model) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HashMap<String, String> weatherMap = new HashMap<>();

        // 获取客户端IP地址
        String ip = IpParseUtil.getIpAddr(request);
        List<String> address = IpParseUtil.parse(ip, null);
        String region = "";
        if (address.size() > 3) {
            region = address.get(2) + address.get(3);
        }

        // 地理位置编码
        Map<String, Object> ipInfoMap = restTemplate.getForObject("https://restapi.amap.com/v3/geocode/geo?key=" + GAO_DE_KEY + "&output=json&address=" + region, Map.class);
        List<Object> geocodes = (List<Object>) ipInfoMap.get("geocodes");
        String adCode = (String) ((LinkedHashMap) geocodes.get(0)).get("adcode");

        // 查询天气信息
        Map<String, Object> weatherMapResponse = restTemplate.getForObject("https://restapi.amap.com/v3/weather/weatherInfo?city=" + adCode + "&key=" + GAO_DE_KEY + "&extensions=all", Map.class);
        
        // 处理天气信息
        processWeatherResponse(weatherMapResponse, weatherMap);

        // 将天气数据添加到模型中
        model.addAttribute("weather", weatherMap);
    }

    private void processWeatherResponse(Map<String, Object> weatherMapResponse, HashMap<String, String> weatherMap) {
        if (CollUtil.isEmpty((Collection<?>) weatherMapResponse.get("forecasts"))) {
            // 如果无法获取天气信息,设置默认值
            weatherMap.put("city", "获取定位失败");
            weatherMap.put("weather", "*");
            weatherMap.put("temperature", "*");
            weatherMap.put("reportTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            weatherMap.put("tomorrowWeather", "*");
            weatherMap.put("tomorrowTemperature", "*");
            weatherMap.put("tomorrowLowTemperature", "*");
        } else {
            // 提取并处理天气信息
            List<Map<String, Object>> forecasts = (List<Map<String, Object>>) weatherMapResponse.get("forecasts");
            String city = forecasts.get(0).get("city").toString().replaceAll("市$", "");
            weatherMap.put("city", city);

            // 实时天气
            Map<String, Object> liveWeather = (Map<String, Object>) forecasts.get(0).get("lives");
            weatherMap.put("weather", (String) liveWeather.get("weather"));
            weatherMap.put("temperature", (String) liveWeather.get("temperature"));
            weatherMap.put("reportTime", (String) liveWeather.get("reporttime"));

            // 天气预报
            List<Map<String, Object>> forecast = (List<Map<String, Object>>) forecasts.get(0).get("casts");
            weatherMap.put("tomorrowWeather", (String) forecast.get(1).get("dayweather"));
            weatherMap.put("tomorrowTemperature", (String) forecast.get(1).get("daytemp"));
            weatherMap.put("tomorrowLowTemperature", (String) forecast.get(1).get("nighttemp"));
        }
    }
}
注意事项
  • 以上代码示例中,IpParseUtil是一个自定义的工具类,用于解析IP地址并获取地理位置信息。你需要根据实际情况实现或替换这部分逻辑。
  • GAO_DE_KEY应该替换为你的高德地图API密钥。
  • RestTemplate用于发起HTTP请求,你可以选择使用WebClient或任何其他HTTP客户端库作为替代。
  • 确保你的Spring Boot项目中已经包含了Spring Cache和Spring Web的支持。

通过以上步骤,你可以在Spring Boot应用中实现异步天气数据获取并利用缓存来优化性能。这不仅可以提升用户体验,还能降低服务器负载,提高应用的整体效率。

相关推荐
卓怡学长12 小时前
w269基于spring boot + vue 候鸟监测数据管理系统
java·数据库·spring boot·spring·intellij-idea
Listen·Rain17 小时前
向量化详解
java·人工智能·spring·机器学习·ai
添砖java_85719 小时前
网页聊天室测试报告
java·spring boot·spring·maven
云计算磊哥@19 小时前
运维开发宝典051-缓存服务Redis集群2
redis·缓存·运维开发
xixingzhe220 小时前
Spring 依赖注入
java·后端·spring
闲猫1 天前
Spring AI 对接Deepseek ChatModel 聊天对话
java·前端·spring
怕孤单的草丛1 天前
缓存管理面临的主要问题
java·数据库·缓存
醇氧1 天前
Spring 容器 Map 注入机制详解
java·后端·spring
ylscode1 天前
Cloudflare Workers Cache 深度解析:边缘缓存如何重塑无服务器性能边界
java·spring·mybatis
沉静的小伙2 天前
Spring事务
java·数据库·spring