從一個天氣預報系統講起
本節通過Spring Boot技術快速實現一個天氣預報系統。
通過這個系統,一方面可以了解Spring Boot的全面用法,為后續創建微服務應用打下基礎;另一方面,該系統會作為本節進行微服務架構改造的非常好的起點。
下面以前面創建的hello-world應用作為基礎進行改造,成為新的應用micro-weather-basic。

開發環境
為了演示本例,需要采用如下開發環境。
. JDK8。
.Gradle 4.0。
. Spring Boot Web Starter 2.0.0.M4。
Apache HttpClient 4.5.3。
數據來源
天氣的數據是天氣預報的實現基礎。本應用與實際的天氣數據無關,理論上可以兼容多種數據來源。但為求簡單,我們在網上找了一個免費、可用的天氣數據接口。
- ·天氣數據來源為中華萬年歷。例如以下兩種方式。
通過城市名稱獲得天氣數據: http://wthrcdn.etouch.cn/weather_mini?city=深圳。
通過城市ID獲得天氣數據: http://wthrcdn.etouch.cn/weather_mini?citykey=101280601。
- ·城市ID列表。每個城市都有一個唯一的ID作為標識,見https:/waylau.com/data/citylist.xml。
調用天氣服務接口示例,這里以“深圳”城市為例,可看到如下天氣數據返回。
{
"data":{
"yesterday":{
"date" :"1日星期五",
"high" :"高溫33℃",
"fx":"無持續風向",
"low" :"低溫26℃",
"fl":"<![CDATA[<3級]]>",
"type":"多云"
},
"city":"深圳",
"aqi" : "72",
"forecast":[
"date":"2日星期六",
"high":"高溫32℃",
"fengli":"<![CDATA[<3級]1>",
"low" :"低溫26℃",
"fengxiang":"無持續風向",
"type" :"陣雨"
},
"date":"3日星期天",
"high":"高溫 29℃",
"fengli":"<![CDATA[5-6級]1>",
"low" :"低溫26℃",
"fengxiang":"無持續風向",
"type":"大雨"
"date":"4日星期一",
"high":"高溫29℃",
"fengli":"<![CDATA[3-4級]1>",
"low":"低溫26℃",
"fengxiang" :"西南風",
"type":"暴雨"
},
"date":"5日星期二",
"high":"高溫31℃",
"fengli":"<![CDATA[<3級]]>",
"low":"低溫27℃",
"fengxiang":"無持續風向",
"type":"陣雨"
"date" :"6日星期三",
"high":"高溫32℃",
"fengli":"<![CDATA[<3級]l>",
"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”,該項目可以直接以之前的“hello-world"應用作為基礎進行修改。
添加Apache HttpClient的依賴,來作為Web請求的客戶端。完整的依賴情況如下。
//依賴關系
dependencies {
//該依賴用于編譯階段
compile('org.springframework.boot:spring-boot-starter-web')
/添加Apache HttpClient依賴
compile('org.apache.httpcomponents:httpclient:4.5.3')
//該依賴用于測試階段
testCompile('org.springframework.boot:spring-boot-starter-test')}

創建天氣信息相關的值對象
創建com.waylau.spring.cloud.weather.vo包,用于存放相關值對象。這些對象都是POJO對象,沒有復雜的業務邏輯
創建天氣信息類 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;
1/省略getter/setter方法
}
昨日天氣信息類Yesterday :
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;
//省略getter/setter方法
}
未來天氣信息類Forecast:
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;
//省略getter/setter方法
}
WeatherResponse作為整個消息的返回對象:
public class WeatherResponse implements Serializable{
private static final long serialversionUID =1L;
private Weather data;1/消息數據
private String status;//消息狀態
private string desc;/l消息描述
//省略getter/setter方法
}
服務接口及實現
創建com.waylau.spring.cloud.weather.service包,用于存放服務接口及其實現。
下面是定義服務的兩個接口方法,一個是根據城市的ID來查詢天氣數據,另一個是根據城市名稱來查詢天氣數據。
package com.waylau.spring.cloud.weather.service;
import com.waylau.spring.cloud.weather.vo.WeatherResponse;
/*★
*天氣數據服務.
大
csince 1.0.o 2017年10月18日
* @author <a href="https://waylau.com">Way Lau</a>
*/
public interface weatherDataservice {
/**
根據城市ID來查詢天氣數據
*
*@param city工d
*return
*/
WeatherResponse getDataByCityId(String cityId);
/**
*根據城市名稱來查詢天氣數據
*
*@param cityId
*@return
*/
WeatherResponse getDataByCityName(String cityName);
}
其服務實現WeatherDataServiceImpl為:
package com.waylau.spring.cloud.weather.service;
import JAVA.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.0bjectMApper;
import com.waylau.spring.cloud.weather.vo.WeatherResponse;
/**
*天氣數據服務.
*
* @since 1.0.0 2017年10月18日
* @author <a href="https://waylau.com">Way Lau</a>
*/
@service
public class WeatherDataServiceImpl implements WeatherDataService {
Autowired
private RestTemplate restTemplate;
private final string WEATHER_API = "http://wthrcdn.etouch.cn/weath-
er_ 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 (工OException e){
e.printStackTrace();
return weather;
其中:
. RestTemplate是一個REST客戶端,默認采用Apache HttpClient來實現;
·返回的天氣信息采用了Jackson來進行反序列化,使其成為WeatherResponse對象。
控制器層
創建com.waylau.spring.cloud.weather.service包,用于存放控制器層代碼??刂破鲗颖┞读薘ESTful API接口。
package com.waylau.spring.cloud.weather.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping:
import org.springframework.web.bind.annotation.RestController;
import com.waylau.spring.cloud.weather.service.WeatherDataService;
import com.waylau.spring.cloud.weather.vo.WeatherResponse;
/★大
*天氣AP工.
*
* @since 1.0.0 2017年10月18日
* author <a href="https://waylau.com">Way Lau</a>
*/
@RestController
RequestMapping("/weather")
public class WeatherController {
@Autowired
private WeatherDataService weatherDataService;
@GetMapping("/cityId/{cityId}")
public WeatherResponse getReportByCityId(CPathVariable("cityId")
string cityId){
return weatherDataService.getDataByCityId(cityId);
}
GetMapping("/cityName/{cityName}")
public WeatherResponse getReportByCityName (CPathVariable ("cityName")
string cityName){
return weatherDataService.getDataByCityName(cityName);}
其中,@RestController會自動將返回的數據進行序列化,使其成為JSON數據格式。
配置類
創建com.waylau.spring.cloud.weather.config包,用于存放配置相關的代碼。創建RestConfiguration
類,該類是RestTemplate 的配置類。
package com.waylau.spring.cloud.weather.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
*REST 配置類.
*
*@since 1.0.02017年10月18日
* @author <a href="https://waylau.com" >Way Lau</a>
*/
Configuration
public class RestConfiguration {
Autowired
private RestTemplateBuilder builder;
@Bean
public RestTemplate restTemplate({
return builder .build();}
}
訪問API
運行項目之后,訪問以下API來進行測試。
- . http://localhost:8080/weather/cityId/101280601。
- http://localhost:8080/weather/cityName/惠州。
能看到如圖6-1所示的天氣API返回的數據。
