Spring Boot实现一个天气预报系统(一)

1.数据来源

{
    "data": {
        "yesterday": {
            "date": "26日星期三",
            "high": "高温 35℃",
            "fx": "南风",
            "low": "低温 23℃",
            "fl": "<![CDATA[3-4级]]>",
            "type": "多云"
        },
        "city": "北京",
        "forecast": [{
            "date": "27日星期四",
            "high": "高温 33℃",
            "fengli": "<![CDATA[<3级]]>",
            "low": "低温 23℃",
            "fengxiang": "北风",
            "type": "多云"
        }, {
            "date": "28日星期五",
            "high": "高温 33℃",
            "fengli": "<![CDATA[<3级]]>",
            "low": "低温 23℃",
            "fengxiang": "南风",
            "type": "多云"
        }, {
            "date": "29日星期六",
            "high": "高温 36℃",
            "fengli": "<![CDATA[<3级]]>",
            "low": "低温 23℃",
            "fengxiang": "东风",
            "type": "多云"
        }, {
            "date": "30日星期天",
            "high": "高温 32℃",
            "fengli": "<![CDATA[3-4级]]>",
            "low": "低温 22℃",
            "fengxiang": "北风",
            "type": "多云"
        }, {
            "date": "1日星期一",
            "high": "高温 34℃",
            "fengli": "<![CDATA[<3级]]>",
            "low": "低温 23℃",
            "fengxiang": "北风",
            "type": "晴"
        }],
        "ganmao": "各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。",
        "wendu": "29"
    },
    "status": 1000,
    "desc": "OK"
}

2.开发环境

  • JDK8

  • Maven

  • Spring Boot Web Starter 2.1.6

  • Apache HttpClient 4.5.3

3.初始化一个Spring Boot项目

(1)添加maven依赖

      
  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
​
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.1.7.RELEASE</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

(2)创建实体类

@Data
public class Weather implements Serializable {
    private String city;
    private String aqi;
    private String wendu;
    private String ganmao;
    private Yesterday yesterday;
    private List<Forecast> forecast;
}
@Data
public class Forecast implements Serializable {
    private String date;
    private String high;
    private String fengxiang;
    private String low;
    private String fengli;
    private String type;
}
@Data
public class Yesterday implements Serializable {
    private String date;
    private String high;
    private String fx;
    private String low;
    private String fl;
    private String type;
}
@Data
public class WeatherResponse implements Serializable {
    /**
     * 消息数据
     */
    private Weather data;
    /**
     * 消息状态
     */
    private String status;
    /**
     * 消息描述
     */
    private String desc;
}

(3)服务接口及实现

public interface WeatherDataService {
​
    /**
     * 根据城市id来查询天气数据
     *
     * @param cityId
     * @return
     */
    WeatherResponse getDataByCityId(String cityId);
​
    /**
     * 根据城市名称来查询天气数据
     *
     * @param cityName
     * @return
     */
    WeatherResponse getDataByCityName(String cityName);
}
@Service
public class WeatherDataServiceImpl implements WeatherDataService {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    private final Logger logger = LoggerFactory.getLogger(WeatherDataServiceImpl.class);
    private final String WEATHER_API = "http://wthrcdn.etouch.cn/weather_mini";
    /**
     * 缓存超时时间
     */
    private final Long TIME_OUT = 1800L;
​
    @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) {
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
        //将调用的uri作为缓存的key
        String strBody = null;
        //先查缓存,没有找到查服务
        if (!stringRedisTemplate.hasKey(uri)) {
            logger.info("未找到 key " + uri);
​
            ResponseEntity<String> response = restTemplate.getForEntity(uri, String.class);
            if (response.getStatusCodeValue() == 200) {
                strBody = response.getBody();
            }
            ops.set(uri, strBody, TIME_OUT, TimeUnit.SECONDS);
        } else {
            logger.info("找到 key " + uri + ",value=" + ops.get(uri));
            strBody = ops.get(uri);
        }
        ObjectMapper mapper = new ObjectMapper();
        WeatherResponse weather = null;
        try {
            weather = mapper.readValue(strBody, WeatherResponse.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return weather;
    }
}

(4)控制层类

@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);
    }
}

(5)配置类

@Configuration
public class Config {
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        // Do any additional configuration here
        return builder.build();
    }
}

(6)Spring配置文件

spring:
  redis:
    host: 127.0.0.1
    database: 0
    password:
    port: 6379

4.为什么使用Redis

缓存的使用与系统的时效性有着非常大的关系。当所使用的系统时效性要求不高时,选择使用缓存是极好的。当系统要求的时效性比较高时,则并不适合使用缓存。

天气数据接口,本身时效性并不是很高,而且又因为时Web服务,在调用过程中,是存在延时的。所以,采用缓存,一方面可以有效减轻访问天气接口服务带来的延时问题;另一方面也可以减轻天气接口的负担,提高并发访问量。

特别是使用第三方免费的天气API,这些API往往对用户的调用次数及频率有一定的限制。所以为了减轻天气API提供方的负荷,并不需要去实时调用其第三方接口。

由于天气数据更新频率的特点(基本上一个小时或半个小时更新一次),因此,在redis中设置了30分钟的失效时间。

5.测试和运行

1.启动Spring Boot项目,启动redis

2.访问接口:http://localhost:8080/weather/cityName/太原,日志如下

未找到 key http://wthrcdn.etouch.cn/weather_mini?city=太原

3.再次访问上面的接口,日志如下

找到 key http://wthrcdn.etouch.cn/weather_mini?city=太原,value={"data":{"yesterday":{"date":"26日星期三","high":"高温 32℃","fx":"东北风","low":"低温 20℃","fl":"<![CDATA[<3级]]>","type":"多云"},"city":"太原","forecast":[{"date":"27日星期四","high":"高温 28℃","fengli":"<![CDATA[<3级]]>","low":"低温 18℃","fengxiang":"北风","type":"小雨"},{"date":"28日星期五","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 16℃","fengxiang":"东北风","type":"多云"},{"date":"29日星期六","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 15℃","fengxiang":"西北风","type":"晴"},{"date":"30日星期天","high":"高温 30℃","fengli":"<![CDATA[<3级]]>","low":"低温 16℃","fengxiang":"北风","type":"晴"},{"date":"1日星期一","high":"高温 31℃","fengli":"<![CDATA[<3级]]>","low":"低温 15℃","fengxiang":"东南风","type":"多云"}],"ganmao":"相对今天出现了较大幅度降温,较易发生感冒,体质较弱的朋友请注意适当防护。","wendu":"27"},"status":1000,"desc":"OK"}

猜你喜欢

转载自blog.csdn.net/fy_java1995/article/details/93907576