SpringBoot搭建一個簡單的天氣預報系統(一)

1. 前言

        先用SpringBoot搭建一個簡單的單體項目,後期,再用SpringCluod把它改造一個微服務架構的項目。其實,寫這篇博客的真實原因也就學習一下SpringCloud。從單體架構過渡到微服務架構,可以深刻地體會到這兩者架構的區別。而且,從今後的發展來看,確實很有必要接觸微服務架構

2. 數據來源

        獲取預報天氣的數據來源:調用第三方接口進行獲取。網上有很多免費的天氣預報接口,隨便找找就有了,也可推薦一個高德地圖的天氣預報接口,它只能根據城市ID獲取天氣信息,但它還有個接口“行政區域查詢”----可以將城市名稱轉換爲城市ID,我覺得比較麻煩,就放棄了。這裏是使用了一個不知名的接口:

  1. 根據城市名獲取天氣信息:http://wthrcdn.etouch.cn/weather_mini?city=深圳
  2. 根據城市ID取天氣信息:http://wthrcdn.etouch.cn/weather_mini?citykey=101280601

        獲取城市列表的json文件

3. 實戰

        因爲此項目是以SpringBoot爲基礎進行搭建的,所以,建議有SpringBoot基礎的讀者再看。

項目結構
在這裏插入圖片描述
項目依賴

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <!-- httpclient -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.2</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

3.1 開發環境

  • IDEA:2018.2(安裝lombok插件)
  • JDK:8
  • MAVEN:3.6.0
  • SpringBoot:2.3.0

3.2 功能需求

  1. 通過城市ID獲取天氣信息
  2. 通過城市名稱獲取天氣信息

這兩個功能可以通過調用第三方接口進行實現

3.3 手動編碼

將接口返回的Json數據進行抽象、封裝成Java對象,方便開發人員操作

3.3.1 vo層

在這裏插入圖片描述
WeatherResponseVO:

@Data
public class WeatherResponseVO implements Serializable {
    private static final long serialVersionUID = -8483256225271502962L;
    private WeatherVO data;
    private Integer status;
    private String desc;
}
  1. @Data註解:可以省略對象的set()/get()方法。@Data註解 與 lombok
  2. 實現Serializable 接口:因爲這些Java對象要通過網絡傳輸,所以,要序列化

WeatherVO:

@Data
public class WeatherVO implements Serializable {
    private static final long serialVersionUID = 4089597935549696545L;
    private String city;
    private String ganmao;
    private String wendu;
    private YesterdayVO yesterday;
    private List<ForecastVO> forecast;
}

YesterdayVO:

@Data
public class YesterdayVO implements Serializable {
    private static final long serialVersionUID = -806309024676977591L;
    private String date;
    private String high;
    private String fx;
    private String low;
    private String fl;
    private String type;
}

ForecastVO:

@Data
public class ForecastVO implements Serializable {
    private static final long serialVersionUID = 1686655601208573654L;
    private String date;
    private String high;
    private String fengli;
    private String low;
    private String fengxiang;
    private String type;
}

3.3.2 service層

        此層是面向接口開發

WeatherDataService:

public interface WeatherDataService {
    // 根據城市id查詢天氣數據
    WeatherResponseVO getDataByCityId(String cityId);

    // 根據城市名稱查詢天氣數據
    WeatherResponseVO getDataByCityName(String cityName);
}

WeatherDataServiceImpl:

@Service
public class WeatherDataServiceImpl implements WeatherDataService {
    private static final String WEATHER_URL = "http://wthrcdn.etouch.cn/weather_mini?";

    @Autowired
    private RestTemplate restTemplate;
    
    @Override
    public WeatherResponseVO getDataByCityId(String cityId) {
        String uri = WEATHER_URL + "citykey=" + cityId;
        return doGetWeather(uri, WeatherResponseVO.class);
    }

    @Override
    public WeatherResponseVO getDataByCityName(String cityName) {
        String uri = WEATHER_URL + "city=" + cityName;
        return doGetWeather(uri, WeatherResponseVO.class);
    }
}
  1. 由於兩個方法中都使用到了部分相同的uri,所以可以提取相同的uri作爲靜態常量
  2. RestTemplate:用於HTTP通信。使用HttpClien進行http通信,代碼複雜,還得手動資源回收等。Springboot — 用更優雅的方式發HTTP請求(RestTemplate詳解)
  3. 由於兩個方法中都是通過RestTemplate進行http通信,並將返回的json數據轉換爲java對象,所以,便可將相同的代碼進行抽取爲一個共同的方法(重構)

doGetWeather():

private <T> T doGetWeather(String uri, Class<T> type) {
    String key = uri;
    String strBody = null;
    ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
    if (StatusCodeConstant.OK == responseEntity.getStatusCodeValue()) {
        strBody = responseEntity.getBody();
    }
    ObjectMapper objectMapper = new ObjectMapper();
    T t = null;
    try {
        t = objectMapper.readValue(strBody, type);
    } catch (Exception e) {
        log.error("Error!", e);
    }
    return t;
}
  1. 使用了 objectMapper.readValue()方法將json字符串轉換爲java對象(json字符串中的key要與對象的屬性名及類型相對應)
  2. 返回值使用了泛型

3.3.3 controller層

WeatherController:

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

    @Autowired
    private WeatherDataService weatherDataService;

    @GetMapping("/cityId/{cityId}")
    public WeatherResponseVO getWeatherByCityId(@PathVariable("cityId") String cityId) {
        return weatherDataService.getDataByCityId(cityId);
    }

    @GetMapping("/cityName/{cityName}")
    public WeatherResponseVO getWeatherByCityName(@PathVariable("cityName") String cityName) {
        return weatherDataService.getDataByCityName(cityName);
    }
}

3.3.4 配置類

@Configuration
public class RestConfig {

    @Autowired
    private RestTemplateBuilder builder;

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

        配置RestTemplate:在啓動時,RestTemplate會在classpath查找中有哪些依賴,因爲已添加HttpClient依賴,所以,RestTemplate會默認把它作爲默認的實現

3.3.5 測試

        啓動main()方法,在瀏覽器中訪問controller層的接口

1)、根據城市ID獲取天氣信息
在這裏插入圖片描述
2)、根據城市名稱獲取天氣信息
在這裏插入圖片描述
好了,這兩個功能已經實現了。接下來就對它進行簡單地優化了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章