Spring Boot实现一个天气预报系统(一)
1.数据来源
-
天气的数据来源为中华万年历
通过城市名称获得天气数据:http://wthrcdn.etouch.cn/weather_mini?city=北京
通过城市id获得天气数据:http://wthrcdn.etouch.cn/weather_mini?citykey=101280601
-
城市id列表
每个城市都有一个唯一的id作为标识:https://waylau.com/data/citylist.xml
-
这里已北京为例,可以看到如下天气数据返回
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 {@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate 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; @Overridepublic WeatherResponse getDataByCityId(String cityId) {String uri = WEATHER_API + "?citykey=" + cityId;return this.doGetWeatherData(uri);} @Overridepublic 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作为缓存的keyString 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 {@Autowiredprivate 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 {@Beanpublic RestTemplate restTemplate(RestTemplateBuilder builder) {// Do any additional configuration herereturn builder.build();} }(6)Spring配置文件
spring:redis:host: 127.0.0.1database: 0password:port: 63794.为什么使用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"}
总结
以上是生活随笔为你收集整理的Spring Boot实现一个天气预报系统(一)的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 枚举类的使用-使用实例域来替代序数
- 下一篇: Spring Boot实现一个天气预报系