閱讀415 返回首頁    go 阿裏雲 go 技術社區[雲棲]


基於Spring Boot的天氣預報服務

本文,我們將基於 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 = "https://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

參考引用

最後更新:2017-09-06 00:04:04

  上一篇:go  西部數據不再競購東芝芯片業務 貝恩資本或成為贏家
  下一篇:go  雲棲社區的第一篇文章