本文共 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 ListcityList; 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 { ListlistCity() 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 ListlistCity() 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()获取缓存中的数据 ValueOperationsops = 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!"); //获取城市列表 ListcityList=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/