博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring Cloud学习笔记4——天气预报系统(3)quartz scheduler定时获取天气数据
阅读量:3941 次
发布时间:2019-05-24

本文共 12191 字,大约阅读时间需要 40 分钟。

开发环境

  • JDK8+
  • Gradle4+
  • Redis 3.2.100
  • Apache HttpClient 4.5.3
  • Spring Boot Web Starter
  • Spring Boot Data Redis Starter
  • Spring Boot Quartz Starter
  • Quartz Scheduler

创建项目

新建项目文件夹:

在这里插入图片描述
micro-weather-redis项目中的源码文件复制粘贴到新项目文件夹中:
在这里插入图片描述
在这里插入图片描述

修改源码

修改build.gradle配置,加入quartz的依赖:

//依赖关系dependencies {
//该依赖用于编译阶段 compile('org.springframework.boot:spring-boot-starter-web') //HttpClient compile('org.apache.httpcomponents:httpclient:4.5.6') //Redis compile('org.springframework.boot:spring-boot-starter-data-redis') //Quartz compile('org.springframework.boot:spring-boot-starter-quartz') //该依赖用于测试阶段 testCompile('org.springframework.boot:spring-boot-starter-test')}

新建包com.study.spring.cloud.weather.job,在包下新建类WeatherDataSyncJob

package com.study.spring.cloud.weather.job;import com.study.spring.cloud.weather.service.WeatherDataService;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.scheduling.quartz.QuartzJobBean;public class WeatherDataSyncJob extends QuartzJobBean {
//在应用中添加日志 private final static Logger logger=LoggerFactory.getLogger(WeatherDataService.class); @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
logger.info("Weather Data Sync Job"); }}

com.study.spring.cloud.weather.config包下新建配置类QuartzConfiguration

package com.study.spring.cloud.weather.config;import com.study.spring.cloud.weather.job.WeatherDataSyncJob;import org.quartz.*;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class QuartzConfiguration {
//JobDetail,定义一个特定的Job @Bean public JobDetail weatherDataSyncJobDetail(){
return JobBuilder.newJob(WeatherDataSyncJob.class).withIdentity("weatherDataSyncJob") .storeDurably().build(); } //Trigger,定义一个特定的Job何时以怎样的形式触发 @Bean public Trigger weatherDataSyncTrigger(){
SimpleScheduleBuilder schedBuilder=SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(2).repeatForever(); return TriggerBuilder.newTrigger().forJob(weatherDataSyncJobDetail()) .withIdentity("weatherDataSyncTrigger").withSchedule(schedBuilder).build(); }}

运行

注意一定要先运行Redis

运行应用:

在这里插入图片描述
运行结果如下:
在这里插入图片描述
可以看到应用根据我们的设置,每隔2秒执行一次Job

准备城市数据

从文件中选取部分城市数据整理成xml文件,如:

xml文件放到项目中:

在这里插入图片描述

获取城市数据

com.study.spring.cloud.weather.vo包下新建类City

package com.study.spring.cloud.weather.vo;import javax.xml.bind.annotation.XmlAccessType;import javax.xml.bind.annotation.XmlAccessorType;import javax.xml.bind.annotation.XmlAttribute;import javax.xml.bind.annotation.XmlRootElement;//声明为xml的根元素@XmlRootElement(name = "d")//声明xml的访问类型为FIELD(字段)@XmlAccessorType(XmlAccessType.FIELD)public class City {
//声明为xml的属性 @XmlAttribute(name = "d1") private String cityId; @XmlAttribute(name = "d2") private String cityName; @XmlAttribute(name = "d3") private String cityCode; @XmlAttribute(name = "d4") private String province; public String getCityId() {
return cityId; } public void setCityId(String cityId) {
this.cityId = cityId; } public String getCityName() {
return cityName; } public void setCityName(String cityName) {
this.cityName = cityName; } public String getCityCode() {
return cityCode; } public void setCityCode(String cityCode) {
this.cityCode = cityCode; } public String getProvince() {
return province; } public void setProvince(String province) {
this.province = province; }}

com.study.spring.cloud.weather.vo包下新建类CityList

package com.study.spring.cloud.weather.vo;import javax.xml.bind.annotation.XmlAccessType;import javax.xml.bind.annotation.XmlAccessorType;import javax.xml.bind.annotation.XmlAttribute;import javax.xml.bind.annotation.XmlRootElement;import java.util.List;//声明为xml的根元素@XmlRootElement(name = "c")//声明xml的访问类型为FIELD(字段)@XmlAccessorType(XmlAccessType.FIELD)public class CityList {
//声明为xml的元素 @XmlElement(name = "d") private List
cityList; public List
getCityList() {
return cityList; } public void setCityList(List
cityList) {
this.cityList = cityList; }}

新建包com.study.spring.cloud.weather.util,在包下新建类XmlBuilder

package com.study.spring.cloud.weather.util;import javax.xml.bind.JAXBContext;import javax.xml.bind.Unmarshaller;import java.io.Reader;import java.io.StringReader;public class XmlBuilder {
//将xml转为指定的POJO public static Object xmlStrToObject(Class
clazz,String xmlStr) throws Exception{
Object xmlObject=null; Reader reader=null; JAXBContext context=JAXBContext.newInstance(clazz); //xml转为对象的接口 Unmarshaller unmarshaller=context.createUnmarshaller(); reader=new StringReader(xmlStr); xmlObject=unmarshaller.unmarshal(reader); if(reader!=null){
reader.close(); } return xmlObject; }}

com.study.spring.cloud.weather.service包下新建接口CityDataService

package com.study.spring.cloud.weather.service;import com.study.spring.cloud.weather.vo.City;import java.util.List;/** * @desc: * * @author: hongliu.ye@hand-china.com * @date: 2018/11/8 */public interface CityDataService {
List
listCity() throws Exception;}

com.study.spring.cloud.weather.service包下新建类CityDataServiceImpl

package com.study.spring.cloud.weather.service;import com.study.spring.cloud.weather.util.XmlBuilder;import com.study.spring.cloud.weather.vo.City;import com.study.spring.cloud.weather.vo.CityList;import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.Resource;import org.springframework.stereotype.Service;import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.List;@Servicepublic class CityDataServiceImpl implements CityDataService {
@Override public List
listCity() throws Exception {
//读取xml文件 Resource resource=new ClassPathResource("cityList.xml"); BufferedReader br=new BufferedReader(new InputStreamReader(resource.getInputStream(),"utf-8")); StringBuffer buffer=new StringBuffer(); String line=""; while((line=br.readLine())!=null){
buffer.append(line); } br.close(); //xml转为Java对象 CityList cityList= (CityList) XmlBuilder.xmlStrToObject(CityList.class, buffer.toString()); return cityList.getCityList(); }}

修改WeatherDataService,新增一个方法syncDataByCityId

package com.study.spring.cloud.weather.service;import com.study.spring.cloud.weather.vo.WeatherResponse;public interface WeatherDataService {
//根据城市ID查询天气数据 WeatherResponse getDataByCityId(String cityId); //根据城市名称查询天气数据 WeatherResponse getDataByCityName(String cityName); //根据城市id同步天气数据 void syncDataByCityId(String cityId); }

修改WeatherDataServiceImpl,新增syncDataByCityId方法的实现:

package com.study.spring.cloud.weather.service;import com.fasterxml.jackson.databind.ObjectMapper;import com.study.spring.cloud.weather.vo.WeatherResponse;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.core.ValueOperations;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Service;import org.springframework.web.client.RestTemplate;import java.io.IOException;import java.util.concurrent.TimeUnit;@Servicepublic class WeatherDataServiceImpl implements WeatherDataService {
//在应用中添加日志 private final static Logger logger=LoggerFactory.getLogger(WeatherDataService.class); private static final String WEATHER_URI="http://wthrcdn.etouch.cn/weather_mini?"; private static final long TIME_OUT=1800L; @Autowired //对rest客户端的封装 private RestTemplate restTemplate; @Autowired //对redis api的封装 private StringRedisTemplate stringRedisTemplate; @Override public WeatherResponse getDataByCityId(String cityId) {
String uri=WEATHER_URI + "citykey=" + cityId; return this.doGetWeather(uri); } @Override public WeatherResponse getDataByCityName(String cityName) {
String uri=WEATHER_URI + "city=" + cityName; return this.doGetWeather(uri); } private WeatherResponse doGetWeather(String uri) {
String key=uri; String strBody=null; ObjectMapper mapper=new ObjectMapper(); WeatherResponse resp=null; //ValueOperations类可通过get()获取缓存中的数据 ValueOperations
ops = stringRedisTemplate.opsForValue(); //先查缓存,缓存有的取缓存中的数据 if(stringRedisTemplate.hasKey(key)){
logger.info("Redis has data"); strBody = ops.get(key); }else{
logger.info("Redis doesn't have data"); //缓存没有,再调用服务接口来获取 //得到json字符串 ResponseEntity
respString = restTemplate.getForEntity(uri, String.class); //判断ResponseEntity的状态码是否为200,为200时取出strBody if(respString.getStatusCodeValue()==200) {
strBody=respString.getBody(); } //数据写入缓存 ops.set(key, strBody, TIME_OUT, TimeUnit.SECONDS); } //用json反序列化成我们想要的数据 try {
/* * strBody:要解析的参数内容,从respString获取 * WeatherResponse.class:要转成的对象类型 */ resp=mapper.readValue(strBody,WeatherResponse.class); }catch(IOException e) {
logger.error("Error!",e); } return resp; } @Override public void syncDataByCityId(String cityId) {
String uri=WEATHER_URI + "citykey=" + cityId; this.saveWeatherData(uri); } //把天气数据放在缓存中 private void saveWeatherData(String uri){
String key=uri; String strBody=null; //ValueOperations类可通过get()获取缓存中的数据 ValueOperations
ops = stringRedisTemplate.opsForValue(); //调用服务接口来获取 ResponseEntity
respString = restTemplate.getForEntity(uri, String.class); //判断ResponseEntity的状态码是否为200,为200时取出strBody if(respString.getStatusCodeValue()==200) {
strBody=respString.getBody(); } //数据写入缓存 ops.set(key, strBody, TIME_OUT, TimeUnit.SECONDS); }}

修改WeatherDataSyncJob

package com.study.spring.cloud.weather.job;import com.study.spring.cloud.weather.service.CityDataService;import com.study.spring.cloud.weather.service.WeatherDataService;import com.study.spring.cloud.weather.vo.City;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.scheduling.quartz.QuartzJobBean;import java.util.List;public class WeatherDataSyncJob extends QuartzJobBean {
//在应用中添加日志 private final static Logger logger=LoggerFactory.getLogger(WeatherDataService.class); @Autowired private CityDataService cityDataService; @Autowired private WeatherDataService weatherDataService; @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
logger.info("Weather Data Sync Job. Start!"); //获取城市列表 List
cityList=null; try {
cityList = cityDataService.listCity(); } catch (Exception e) {
logger.error("Exception!",e); } //遍历城市id获取天气 for(City city:cityList){
String cityId=city.getCityId(); logger.info("Weather Data Sync Job, cityId:"+cityId); weatherDataService.syncDataByCityId(cityId); } logger.info("Weather Data Sync Job. End!"); }}

修改QuartzConfiguration的更新频率:

package com.study.spring.cloud.weather.config;import com.study.spring.cloud.weather.job.WeatherDataSyncJob;import org.quartz.*;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class QuartzConfiguration {
//更新频率 private static final int TIME = 1800; //JobDetail,定义一个特定的Job @Bean public JobDetail weatherDataSyncJobDetail(){
return JobBuilder.newJob(WeatherDataSyncJob.class).withIdentity("weatherDataSyncJob") .storeDurably().build(); } //Trigger,定义一个特定的Job何时以怎样的形式触发 @Bean public Trigger weatherDataSyncTrigger(){
SimpleScheduleBuilder schedBuilder=SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(TIME).repeatForever(); return TriggerBuilder.newTrigger().forJob(weatherDataSyncJobDetail()) .withIdentity("weatherDataSyncTrigger").withSchedule(schedBuilder).build(); }}

运行

注意一定要先运行Redis

运行应用:

在这里插入图片描述
运行结果如下:
在这里插入图片描述
在这里插入图片描述
Redis Desktop Manager查看:
运行Redis Desktop Manager
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

转载地址:http://ngiwi.baihongyu.com/

你可能感兴趣的文章
android studio drawable目录的分辨率
查看>>
j2me MIDP2.0已移植到 MT6225 GEMINI 0812 版本上
查看>>
MIDP2.1规范的新特性
查看>>
J2ME开发
查看>>
Java ME平台
查看>>
Unicode 汉字内码表
查看>>
MT6235
查看>>
mtk camera isp
查看>>
j2me 扑克发牌算法实现
查看>>
J2ME贪吃蛇源代码——200行左右,包含详细注释
查看>>
J2ME游戏源代码免费下载——国外Digiment公司商业化代码
查看>>
手机银行技术应用探讨
查看>>
角色扮演游戏引擎的设计原理
查看>>
j2me开发FAQ整理
查看>>
J2ME程序开发新手入门九大要点
查看>>
双向搜索算法
查看>>
日本GAME製作方式
查看>>
移动行业术语资料
查看>>
3G到来将全面颠覆SP、CP游戏规则
查看>>
射击游戏中跟踪弹及小角度移动的开发
查看>>