封印在家, 寫個新型肺炎疫情小工具

這個春節, 應該會讓咱們永世難忘! 天天早上醒來第一件事就是看新型肺炎相關的消息, 白天就是宅在家作飯/吃飯/看電視. 兩天前艱難地回到上海了, 春節假期延長了, 卻無意幹正事, 天天就在那刷疫情相關的消息. 在刷掘金沸點時, 看到有的網友用天行數據開放的 API 作了個疫情小工具. 我想閒着也無聊, 我也來寫一個吧!css

概述

體驗網址: kaiyuanshuwu.cn/ncov.html, 截圖以下:html

主要功能:前端

  • 全國, 以及分省份/城市的確診病例/疑似病例/死亡人數/治癒人數
  • 疫情相關消息/謠言滾動播報
  • 新型肺炎確診患者同行程查詢

主要技術棧:vue

  • 數據
    • 開放 API: 天行數據
    • retrofit2, 將 API 轉化爲 "微服務"
    • redis, 緩存 10min, 減小對 API 的請求 (天行也是大約 10min 更新一次數據)
  • 後端
    • Java
    • Spring Boot
  • 前端
    • Vue
    • Element UI
    • EChart

數據對接

登陸天行數據, 申請相關 API 接口. 爲了更優化地對接 API 接口, 咱們用 retrofit2, 將其轉換爲 "微服務" 形式. 引入以下兩個依賴java

<dependency>
  <groupId>com.squareup.retrofit2</groupId>
  <artifactId>retrofit</artifactId>
  <version>2.6.2</version>
</dependency>
<dependency>
  <groupId>com.squareup.retrofit2</groupId>
  <artifactId>converter-jackson</artifactId>
  <version>2.0.2</version>
</dependency>
複製代碼

引入 converter-jackson 的目的是 json 轉 java 對象. 定義 TianService 接口, 將 API 映射爲對應的接口方法, 而後增長配置文件 TianConfig, 生成 tianService Bean.webpack

@Configuration
public class TianConfig {
    @Autowired
    private GlobalSetting globalSetting;

    @Autowired
    private Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder;

    @Bean
    public TianService tianService() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(globalSetting.getTianHost())
                .client(new OkHttpClient.Builder()
                        .connectTimeout(3000, TimeUnit.MILLISECONDS)
                        .writeTimeout(1000, TimeUnit.MILLISECONDS)
                        .readTimeout(1000, TimeUnit.MILLISECONDS).build())
                .addConverterFactory(JacksonConverterFactory.create(
                        jackson2ObjectMapperBuilder.build()))
                .build();
        return retrofit.create(TianService.class);
    }
}
複製代碼

字段重命名

在對接 API 時, 常常會須要對 JSON 串的字段進行重命名, 好比下劃線改駝峯. 建議使用 @JsonProperty 註解. 不過, 若是這個 Java 對象通過 Spring MVC 再次轉爲 JSON 串時, 又恢復原樣了, 由於 Spring MVC 也是用的 jackson.ios

優雅的解決方案是用 fastjson 替換 Spring MVC 的默認配置.git

@Configuration
public class FastJsonHttpMessageConverterConfig {
    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        SerializeConfig serializeConfig = SerializeConfig.globalInstance;

        // 初始化一個轉換器配置
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializeConfig(serializeConfig);
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat,
                SerializerFeature.WriteNonStringKeyAsString,
                SerializerFeature.DisableCircularReferenceDetect);

        // 初始化轉換器
        FastJsonHttpMessageConverter fastConvert = new FastJsonHttpMessageConverter();
        fastConvert.setFastJsonConfig(fastJsonConfig);
        fastConvert.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON_UTF8));

        // 將配置設置給轉換器並添加到HttpMessageConverter轉換器列表中
        return new HttpMessageConverters(fastConvert);
    }
}
複製代碼

數據緩存

接下來, 在咱們 Controller 層調用 TianService 服務便可, 爲了減小對 API 的請求次數, 增長一個 Redis 緩存, 設置 Key 的緩存時間爲 10min.github

因爲個人雲服務器以前沒有安裝 Redis, 這裏先裝一下web

yum install -y redis
service redis start
chkconfig redis on
複製代碼

接下來就能夠正常使用了. Java 訪問 Redis, 咱們用 spring-boot-starter-data-redis, 先引入依賴

<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
複製代碼

版本號 spring-boot 管理好了. 注意這裏須要引入 jedis, 或 common-pool2, 用於生成鏈接池相關 Bean. 因爲 spring-data-redis 自帶的 redisTemplate Bean 是 RedisTemplate<Object, Object>, 使用不方便, 所以咱們從新定義以下.

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }
}
複製代碼

如今就能夠很方便地緩存/讀取數據啦!

redisTemplate.opsForValue().set(KEY_NCOV, response, 10, TimeUnit.MINUTES)
redisTemplate.opsForValue().get(KEY_NCOV)
複製代碼

視圖層

採用先後端徹底分離的方式, 先增長一個 /ncov.html 頁面, 它本質是一個 FreeMarker 頁面, 引入了 Vue 打包後的 js 和 css. 其餘數據採用 api 的方式給到前端. 前端用 axios 將數據引入 Vuex Store 中.

新增 src/ncov.js 文件, 並添加到 webpack 構建配置的入口列表中. 入口文件的主要內容是

new Vue({
  el: '#app',
  store,
  render: h => h(NCov)
});
複製代碼

其中 NCov 就是主要的視圖頁面.

疫情地圖

丁香醫生等平臺提供的疫情地圖, 用的是分段函數劃分的嚴重等級, 這樣模糊了一些區別. 這裏用 EChart 的地圖工具, 而後用「確診病例數除以100」給地圖上色.

我在 Vue 中使用 EChart, 通常用本身簡單封裝的 EChart 組件. 注意: 爲了使用地圖工具, 還須要引入對應的 js.

import EChart from 'hui-vue/src/components/EChart';
import 'echarts/map/js/china';
複製代碼

進一步思考

宅在家的這段時間, 閱讀了不少內容, 其中, 感觸最深的是一位CEO給員工的防疫指南:在不肯定的世界強悍地活帶來的思考. 自我隔離這段時間是很好的自學, 提高自我, 思考將來的時期.

咱們正在經歷一次可能漫長而危險的不肯定性時期, 人民和國家損失慘重, 以人爲本, 不計成本地建設 "小湯山" 醫院, 壯士斷腕, 作出封城封村, 延遲開工開學的決定. 每一個人都關注疫情發展, 自我隔離, 堅信疫情拐點很快就會到來!!!

更多相關資料

相關文章
相關標籤/搜索