基于Spring Boot的天气预报服务

简介: 本文,我们将基于 Spring Boot 技术来实现一个微服务天气预报服务接口——micro-weather-basic。micro-weather-basic 的作用是实现简单的天气预报功能,可以根据不同的城市,查询该城市的实时天气情况。

本文,我们将基于 Spring Boot 技术来实现一个微服务天气预报服务接口——micro-weather-basic。micro-weather-basic 的作用是实现简单的天气预报功能,可以根据不同的城市,查询该城市的实时天气情况。

开发环境

  • Gradle 4.0
  • Spring Boot 1.5.6
  • Apache HttpClient 1.5.3

数据来源

理论上,天气的数据是天气预报的实现基础。本应用与实际的天气数据无关,理论上,可以兼容多种数据来源。但为求简单,我们在网上找了一个免费、可用的天气数据接口。

调用天气服务接口示例,我们以“深圳”城市为例,可用看到如下天气数据返回。

{
    "data": {
        "yesterday": {
            "date": "1日星期五",
            "high": "高温 33℃",
            "fx": "无持续风向",
            "low": "低温 26℃",
            "fl": "<![CDATA[<3级]]>",
            "type": "多云"
        },
        "city": "深圳",
        "aqi": "72",
        "forecast": [
            {
                "date": "2日星期六",
                "high": "高温 32℃",
                "fengli": "<![CDATA[<3级]]>",
                "low": "低温 26℃",
                "fengxiang": "无持续风向",
                "type": "阵雨"
            },
            {
                "date": "3日星期天",
                "high": "高温 29℃",
                "fengli": "<![CDATA[5-6级]]>",
                "low": "低温 26℃",
                "fengxiang": "无持续风向",
                "type": "大雨"
            },
            {
                "date": "4日星期一",
                "high": "高温 29℃",
                "fengli": "<![CDATA[3-4级]]>",
                "low": "低温 26℃",
                "fengxiang": "西南风",
                "type": "暴雨"
            },
            {
                "date": "5日星期二",
                "high": "高温 31℃",
                "fengli": "<![CDATA[<3级]]>",
                "low": "低温 27℃",
                "fengxiang": "无持续风向",
                "type": "阵雨"
            },
            {
                "date": "6日星期三",
                "high": "高温 32℃",
                "fengli": "<![CDATA[<3级]]>",
                "low": "低温 27℃",
                "fengxiang": "无持续风向",
                "type": "阵雨"
            }
        ],
        "ganmao": "风较大,阴冷潮湿,较易发生感冒,体质较弱的朋友请注意适当防护。",
        "wendu": "29"
    },
    "status": 1000,
    "desc": "OK"
}

我们通过观察数据,来了解每个返回字段的含义。

  • "city": 城市名称
  • "aqi": 空气指数,
  • "wendu": 实时温度
  • "date": 日期,包含未来5天
  • "high":最高温度
  • "low": 最低温度
  • "fengli": 风力
  • "fengxiang": 风向
  • "type": 天气类型

以上数据,是我们需要的天气数据的核心数据,但是,同时也要关注下面两个字段:

  • "status": 接口调用的返回状态,返回值“1000”,意味着数据是接口正常
  • "desc": 接口状态的描述,“OK”代表接口正常

重点关注返回值不是“1000”的情况,说明,这个接口调用异常了。

初始化一个 Spring Boot 项目

初始化一个 Spring Boot 项目 micro-weather-basic,该项目可以直接在我们之前章节课程中的 basic-gradle 项目基础进行修改。同时,为了优化项目的构建速度,我们对Maven中央仓库地址和 Gradle Wrapper 地址做了调整。其中细节暂且不表,读者可以自行参阅源码,或者学习笔者所著的《Spring Boot 教程》(https://github.com/waylau/spring-boot-tutorial)。其原理,我也整理到我的博客中了:

项目配置

添加 Apache HttpClient 的依赖,来作为我们Web请求的客户端。

// 依赖关系
dependencies {
    //...
 
    // 添加  Apache HttpClient 依赖
    compile('org.apache.httpcomponents:httpclient:4.5.3')

     //...
}

创建天气信息相关的值对象

创建com.waylau.spring.cloud.vo包,用于相关值对象。创建天气信息类 Weather

public class Weather implements Serializable {
     
    private static final long serialVersionUID = 1L;
        
    private String city;
    private String aqi;
    private String wendu;
    private String ganmao;
    private Yesterday yesterday;
    private List<Forecast> forecast;
 
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public String getAqi() {
        return aqi;
    }
    public void setAqi(String aqi) {
        this.aqi = aqi;
    }
    public String getWendu() {
        return wendu;
    }
    public void setWendu(String wendu) {
        this.wendu = wendu;
    }
    public String getGanmao() {
        return ganmao;
    }
    public void setGanmao(String ganmao) {
        this.ganmao = ganmao;
    }
    public Yesterday getYesterday() {
        return yesterday;
    }
    public void setYesterday(Yesterday yesterday) {
        this.yesterday = yesterday;
    }
    public List<Forecast> getForecast() {
        return forecast;
    }
    public void setForecast(List<Forecast> forecast) {
        this.forecast = forecast;
    }
}

昨日天气信息:

public class Yesterday implements Serializable {
 
    private static final long serialVersionUID = 1L;
    
    private String date;
    private String high;
    private String fx;
    private String low;
    private String fl;
    private String type;

    public Yesterday() {

    }
    
    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getHigh() {
        return high;
    }

    public void setHigh(String high) {
        this.high = high;
    }

    public String getFx() {
        return fx;
    }

    public void setFx(String fx) {
        this.fx = fx;
    }

    public String getLow() {
        return low;
    }

    public void setLow(String low) {
        this.low = low;
    }

    public String getFl() {
        return fl;
    }

    public void setFl(String fl) {
        this.fl = fl;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

}

未来天气信息:

public class Forecast implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    private String date;
    private String high;
    private String fengxiang;
    private String low;
    private String fengli;
    private String type;

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getHigh() {
        return high;
    }

    public void setHigh(String high) {
        this.high = high;
    }

    public String getFengxiang() {
        return fengxiang;
    }

    public void setFengxiang(String fengxiang) {
        this.fengxiang = fengxiang;
    }

    public String getLow() {
        return low;
    }

    public void setLow(String low) {
        this.low = low;
    }

    public String getFengli() {
        return fengli;
    }

    public void setFengli(String fengli) {
        this.fengli = fengli;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Forecast() {

    }
 
}

WeatherResponse 作为整个消息的返回对象

public class WeatherResponse implements Serializable {

    private static final long serialVersionUID = 1L;

    private Weather data; // 消息数据
    private String status; // 消息状态
    private String desc; // 消息描述

    public Weather getData() {
        return data;
    }

    public void setData(Weather data) {
        this.data = data;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

}

服务接口及实现

定义了获取服务的两个接口方法

public interface WeatherDataService {

    /**
     * 根据城市ID查询天气数据
     * @param cityId
     * @return
     */
    WeatherResponse getDataByCityId(String cityId);
    
    /**
     * 根据城市名称查询天气数据
     * @param cityId
     * @return
     */
    WeatherResponse getDataByCityName(String cityName);
}

其实现为:

@Service
public class WeatherDataServiceImpl implements WeatherDataService {

    @Autowired
    private RestTemplate restTemplate;

    private final String WEATHER_API = "http://wthrcdn.etouch.cn/weather_mini";

    @Override
    public WeatherResponse getDataByCityId(String cityId) {
        String uri = WEATHER_API + "?citykey=" + cityId;
        return this.doGetWeatherData(uri);
    }

    @Override
    public WeatherResponse getDataByCityName(String cityName) {
        String uri = WEATHER_API + "?city=" + cityName;
        return this.doGetWeatherData(uri);
    }

    private WeatherResponse doGetWeatherData(String uri) {
        ResponseEntity<String> response = restTemplate.getForEntity(uri, String.class);
        String strBody = null;

        if (response.getStatusCodeValue() == 200) {
            strBody = response.getBody();
        }

        ObjectMapper mapper = new ObjectMapper();
        WeatherResponse weather = null;

        try {
            weather = mapper.readValue(strBody, WeatherResponse.class);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return weather;
    }

}

返回的天气信息采用了 Jackson 来进行反序列化成为 WeatherResponse 对象。

控制器层

控制器层暴露了RESTful API 地址。

@RestController
@RequestMapping("/weather")    
public class WeatherController {

    @Autowired
    private WeatherDataService weatherDataService;
    
    @GetMapping("/cityId/{cityId}")
    public WeatherResponse getReportByCityId(@PathVariable("cityId") String cityId) {
        return weatherDataService.getDataByCityId(cityId);
    }
    
    @GetMapping("/cityName/{cityName}")
    public WeatherResponse getReportByCityName(@PathVariable("cityName") String cityName) {
        return weatherDataService.getDataByCityName(cityName);
    }

}

@RestController自动会将返回的数据,序列化成 JSON数据格式。

配置类

RestConfiguration 是 RestTemplate 的配置类。

@Configuration
public class RestConfiguration {

    @Autowired  
    private RestTemplateBuilder builder;  

    @Bean  
    public RestTemplate restTemplate() {  
        return builder.build();  
    }

}

访问API

运行项目之后,访问项目的 API :

能看到如下的数据返回

weather-data

源码

本章节的源码,见 https://github.com/waylau/spring-cloud-tutorial/ samples目录下的micro-weather-basic

参考引用

目录
相关文章
|
人工智能 Java Serverless
【MCP教程系列】搭建基于 Spring AI 的 SSE 模式 MCP 服务并自定义部署至阿里云百炼
本文详细介绍了如何基于Spring AI搭建支持SSE模式的MCP服务,并成功集成至阿里云百炼大模型平台。通过四个步骤实现从零到Agent的构建,包括项目创建、工具开发、服务测试与部署。文章还提供了具体代码示例和操作截图,帮助读者快速上手。最终,将自定义SSE MCP服务集成到百炼平台,完成智能体应用的创建与测试。适合希望了解SSE实时交互及大模型集成的开发者参考。
9753 60
|
3月前
|
Prometheus 监控 Cloud Native
Docker 部署 Prometheus 和 Grafana 监控 Spring Boot 服务
Docker 部署 Prometheus 和 Grafana 监控 Spring Boot 服务实现步骤
|
7月前
|
人工智能 自然语言处理 Java
对话即服务:Spring Boot整合MCP让你的CRUD系统秒变AI助手
本文介绍了如何通过Model Context Protocol (MCP) 协议将传统Spring Boot服务改造为支持AI交互的智能系统。MCP作为“万能适配器”,让AI以统一方式与多种服务和数据源交互,降低开发复杂度。文章以图书管理服务为例,详细说明了引入依赖、配置MCP服务器、改造服务方法(注解方式或函数Bean方式)及接口测试的全流程。最终实现用户通过自然语言查询数据库的功能,展示了MCP在简化AI集成、提升系统易用性方面的价值。未来,“对话即服务”有望成为主流开发范式。
5253 7
|
6月前
|
存储 Java 定位技术
SpringBoot整合高德地图完成天气预报功能
本文介绍了如何在SpringBoot项目中整合高德地图API实现天气预报功能。从创建SpringBoot项目、配置依赖和申请高德地图API开始,详细讲解了实体类设计、服务层实现(调用高德地图API获取实时与预报天气数据)、控制器层接口开发以及定时任务的设置。通过示例代码,展示了如何获取并处理天气数据,最终提供实时天气与未来几天天气预报的接口。文章还提供了测试方法及运行步骤,帮助开发者快速上手并扩展功能。
|
9月前
|
XML Java 应用服务中间件
Spring Boot 两种部署到服务器的方式
本文介绍了Spring Boot项目的两种部署方式:jar包和war包。Jar包方式使用内置Tomcat,只需配置JDK 1.8及以上环境,通过`nohup java -jar`命令后台运行,并开放服务器端口即可访问。War包则需将项目打包后放入外部Tomcat的webapps目录,修改启动类继承`SpringBootServletInitializer`并调整pom.xml中的打包类型为war,最后启动Tomcat访问应用。两者各有优劣,jar包更简单便捷,而war包适合传统部署场景。需要注意的是,war包部署时,内置Tomcat的端口配置不会生效。
2196 17
Spring Boot 两种部署到服务器的方式
|
8月前
|
网络协议 Java Shell
java spring 项目若依框架启动失败,启动不了服务提示端口8080占用escription: Web server failed to start. Port 8080 was already in use. Action: Identify and stop the process that’s listening on port 8080 or configure this application to listen on another port-优雅草卓伊凡解决方案
java spring 项目若依框架启动失败,启动不了服务提示端口8080占用escription: Web server failed to start. Port 8080 was already in use. Action: Identify and stop the process that’s listening on port 8080 or configure this application to listen on another port-优雅草卓伊凡解决方案
423 7
|
7月前
|
Java 数据库 微服务
微服务——SpringBoot使用归纳——Spring Boot中的项目属性配置——指定项目配置文件
在实际项目中,开发环境和生产环境的配置往往不同。为简化配置切换,可通过创建 `application-dev.yml` 和 `application-pro.yml` 分别管理开发与生产环境配置,如设置不同端口(8001/8002)。在 `application.yml` 中使用 `spring.profiles.active` 指定加载的配置文件,实现环境快速切换。本节还介绍了通过配置类读取参数的方法,适用于微服务场景,提升代码可维护性。课程源码可从 [Gitee](https://gitee.com/eson15/springboot_study) 下载。
258 0
|
9月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue实现的家政服务管理平台设计与实现(计算机毕设项目实战+源码+文档)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
|
9月前
|
JavaScript NoSQL Java
基于SpringBoot+Vue实现的大学生就业服务平台设计与实现(系统源码+文档+数据库+部署等)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!