java集成天气信息

天气信息提供商有很多,有心知天气,聚合数据,还有一些是跟阿里云合作的,我这边根据项目需求和收费情况选择了心知天气,因为心知天气免费版每小时提供的接口调用次数限制是400次/小时,所以这里采用redis进行数据缓存来解决该问题

1.到官网进行注册

https://www.seniverse.com/

注册后登入可以获得一个key值

175427_gttf_2988360.png

2.获得key值后就可以进行https接口调用了

2.1 创建一个心知天气信息工具类

该类用于获取天气信息和生活指数两个接口,这两个接口返回ResponseEntity<String>对象,这是spring提供的标准对象,将在业务层对该对象进行解析

package com.lantaiyuan.ebus.common.weather.seniverse;

import org.springframework.http.ResponseEntity;
/**
 * 描述:心知天气
 * 作者:温海金
 * 最后更改时间:下午2:16:19
 */
public class SeniverseWeatherHelper {
	/**
	 * 注册KEY值
	 */
	private static String KEY = "2poa1sq8xbc0dnxo";	
	/**
	 * 天气接口前缀
	 */
	public static String WEATHER_URL_PRE = "https://api.seniverse.com/v3/weather/now.json?language=zh-Hans&unit=c";
	/**
	 * 生活指数接口前缀
	 */
	public static String LIFE_URL_PRE = "https://api.seniverse.com/v3/life/suggestion.json?language=zh-Hans";
	/**
	 * 功能描述:返回接口调用结果
	 * 作者:温海金
	 * 最后更改时间 : 2017年4月19日 下午2:40:10
	 */
	public static ResponseEntity<String> getSeniverseInterfaceResult(String URL, String cityName) {
		return getResultOfRequest(URL+"&location="+cityName.trim()+"&key="+KEY);
	}
	
	/**
	 * 功能描述:获取URL执行结果
	 * 作者:温海金
	 * 最后更改时间 : 2017年4月19日 下午2:40:10
	 */
	private static ResponseEntity<String> getResultOfRequest(String url) {
		return RestTemplateSigleton.getInstance().getForEntity(url, String.class);
	}
	
}

2.2 定义一个单例的RestTemplate对象

在上面的工具类中,https接口的访问是通过spring的RestTemplate来操作的:

/**
	 * 功能描述:获取URL执行结果
	 * 作者:温海金
	 * 最后更改时间 : 2017年4月19日 下午2:40:10
	 */
	private static ResponseEntity<String> getResultOfRequest(String url) {
		return RestTemplateSigleton.getInstance().getForEntity(url, String.class);
	}

这是spring提供的rest接口访问模板对象

package com.lantaiyuan.ebus.common.weather.seniverse;

import org.springframework.web.client.RestTemplate;
/**
 * 描述:http请求模板对象实例类
 * 作者:温海金
 * 最后更改时间:下午2:19:49
 */
public class RestTemplateSigleton {
	/**
	 * spring提供的rest接口访问模板对象
	 */
	private static RestTemplate restTemplate = null;
	
	public static RestTemplate getInstance() {
		if(restTemplate == null) {
			synchronized (RestTemplateSigleton.class) {
				if(restTemplate == null) {
					restTemplate = new RestTemplate();
				}
			}
		}
		return restTemplate;
	}
}

3 通过alibaba提供的JSON工具类解析ResponseEntity<String>对象

package com.lantaiyuan.ebus.custom.service.impl;

import java.util.Collections;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lantaiyuan.ebus.common.weather.seniverse.SeniverseWeatherHelper;
import com.lantaiyuan.ebus.custom.model.NoticeHistory;
import com.lantaiyuan.ebus.custom.model.SeniverseLife;
import com.lantaiyuan.ebus.custom.model.SeniverseWeather;
import com.lantaiyuan.ebus.custom.model.SeniverseWeatherAndLife;
import com.lantaiyuan.ebus.custom.model.WeatherInfoAndNoticeHistory;
import com.lantaiyuan.ebus.custom.service.NoticeHistoryServiceI;
import com.lantaiyuan.ebus.custom.service.WeatherServiceI;

@CacheConfig(cacheNames="weatherInfo")
@Service("weatherService")
public class WeatherServiceImpl implements WeatherServiceI {

	@Resource
	private NoticeHistoryServiceI noticeHistoryService;

	/**
	 * 功能描述:得到聚合天气及生活指数信息
	 * 作者:温海金
	 * 最后更改时间 : 2017年4月20日 下午4:47:18
	 */
	@Cacheable
	private SeniverseWeatherAndLife getSeniverseWeather(String cityName) {
		//1.得到天气信息
		ResponseEntity<String> weatherInfo = SeniverseWeatherHelper.getSeniverseInterfaceResult(SeniverseWeatherHelper.WEATHER_URL_PRE, cityName);
		String weatherBody = weatherInfo.getBody();
		JSONObject weatherJSONObj = JSONObject.parseObject(weatherBody);
		//得到天气对象数组
		JSONArray weatherArray = weatherJSONObj.getJSONArray("results");
		//得到数组内的对象
		JSONObject weatherObject = weatherArray.getJSONObject(0);
		//得到当前天气信息对象
		JSONObject now = weatherObject.getJSONObject("now");
		SeniverseWeather seniverseWeather = JSON.parseObject(now.toJSONString(), SeniverseWeather.class);
		//2.得到生活指数
		ResponseEntity<String> lifeInfo = SeniverseWeatherHelper.getSeniverseInterfaceResult(SeniverseWeatherHelper.LIFE_URL_PRE, cityName);
		JSONObject lifeJsonObj = JSONObject.parseObject(lifeInfo.getBody());
		JSONObject lifeObject = lifeJsonObj.getJSONArray("results").getJSONObject(0);
		JSONObject suggestion = lifeObject.getJSONObject("suggestion");
		
		String flu = suggestion.getJSONObject("flu").get("brief").toString();//感冒指数
		String sport = suggestion.getJSONObject("sport").get("brief").toString();//运动指数
		String uv = suggestion.getJSONObject("uv").get("brief").toString();//紫外线
		return new SeniverseWeatherAndLife(seniverseWeather, new SeniverseLife(sport, flu, uv));
	}
	
	/**
	 * 功能描述:根据用户id得到通知记录信息
	 * 作者:温海金
	 * 最后更改时间 : 2017年4月19日 下午5:41:10
	 */
	private List<NoticeHistory> getHistorysByUserId(String userId) {
		return noticeHistoryService.getNoticeHistorysByUserId(userId);
	}

	/**
	 * 功能描述:得到心知天气信息(包括天气及生活指数信息)和用户的历史通知记录
	 * 作者:温海金
	 * 最后更改时间 : 2017年4月20日 下午3:15:08
	 */
	@Override
	public WeatherInfoAndNoticeHistory getSeniverseWeatherAndNoticeHistory(String cityName, String userId) {
		//1.得到天气信息
		SeniverseWeatherAndLife seniverseWeather = this.getSeniverseWeather(cityName);
		//2.得到历史通知记录信息
		List<NoticeHistory> noticeHistorys;
		if(StringUtils.isEmpty(userId)) {//未登入用户返回空集合
			noticeHistorys = Collections.emptyList();
		} else {
			noticeHistorys = getHistorysByUserId(userId);
		}
		return new WeatherInfoAndNoticeHistory(seniverseWeather, noticeHistorys);
	}
	
}

以上方法涉及到json对象的解析,以下通过断点调试查看alibaba的json解析器是在什么情况下使用的

3.1 通过spring的RestTemplate获取的心知天气信息weatherInfo格式如下:

<200 OK,{"results":[{"location":{"id":"WS10730EM8EV","name":"深圳","country":"CN","path":"深圳,深圳,广东,中国","timezone":"Asia/Shanghai","timezone_offset":"+08:00"},"now":{"text":"多云","code":"4","temperature":"27"},"last_update":"2017-04-20T18:00:00+08:00"}]},{Date=[Thu, 20 Apr 2017 10:21:35 GMT], Content-Type=[application/json; charset=utf-8], Content-Length=[266], Connection=[keep-alive], Cache-Control=[no-cache], Pragma=[no-cache], Expires=[-1]}>

3.2 通过weatherInfo.getBody()得到具体对象信息

{"results":[{"location":{"id":"WS10730EM8EV","name":"深圳","country":"CN","path":"深圳,深圳,广东,中国","timezone":"Asia/Shanghai","timezone_offset":"+08:00"},"now":{"text":"多云","code":"4","temperature":"27"},"last_update":"2017-04-20T18:00:00+08:00"}]}

这是一个字符串,通过JSONObject.parseObject(String str)转化为JSONObject对象weatherJSONObj

将其格式化如下:

183419_XIAy_2988360.png

 

3.3 获取JSONObject对象中的数组

weatherJSONObj对象中的results是一个数组

通过JSONArray weatherArray = weatherJSONObj.getJSONArray("results");来得到数组信息:

weatherArray

[{"last_update":"2017-04-20T18:15:00+08:00","location":{"country":"CN","id":"WS10730EM8EV","name":"深圳","path":"深圳,深圳,广东,中国","timezone":"Asia/Shanghai","timezone_offset":"+08:00"},"now":{"code":"4","temperature":"26","text":"多云"}}]

183827_5NsF_2988360.png

3.4 获取数组中的对象

数组weatherArray中只有一个对象,通过JSONArray的getJSONObject(int  index)获得该对象

JSONObject weatherObject = weatherArray.getJSONObject(0);

weatherObject 格式如下:

{"last_update":"2017-04-20T18:15:00+08:00","location":{"country":"CN","id":"WS10730EM8EV","name":"深圳","path":"深圳,深圳,广东,中国","timezone":"Asia/Shanghai","timezone_offset":"+08:00"},"now":{"code":"4","temperature":"26","text":"多云"}}

184159_d0Pe_2988360.png

再通过JSONObject now = weatherObject.getJSONObject("now");得到对象中今天的天气信息:

now的结构:{"code":"4","temperature":"26","text":"多云"}

3.5 获取JSONObject中的具体属性值

String text = now.get("text").toString();

该方法得到的值为:“多云”

4 JSONObject对象与javaBean的转化

4.1 调用以下方法将当前天气信息转化为javaBean

SeniverseWeather seniverseWeather = JSON.parseObject(now.toJSONString(), SeniverseWeather.class);

javaBean的定义如下:

package com.lantaiyuan.ebus.custom.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
/**
 * 描述:心知天气-天气信息对象
 * 作者:温海金
 * 最后更改时间:下午6:53:11
 */
public class SeniverseWeather {
	/**
	 * 天气情况
	 */
	private String text;
	/**
	 * 返回编码(不展示给前端)
	 */
	@JsonIgnore
	private String code;
	/**
	 * 温度
	 */
	private String temperature;
	
	public String getText() {
		return text;
	}
	public void setText(String text) {
		this.text = text;
	}
	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
	public String getTemperature() {
		return temperature;
	}
	public void setTemperature(String temperature) {
		this.temperature = temperature;
	}
}

4.2 @JsonIgnore注解的使用

在以上javaBean中,使用@JsonIgnore注解的作用是隐藏code字段,不将“返回编码信息”返回给前端

5 给天气接口加缓存

心知天气每小时调用400次,所以将该接口的调用结果缓存到redis中

1.在spring配置文件中添加缓存配置信息

<bean id="redisCacheConfig" class="com.lantaiyuan.ebus.common.redis.RedisCacheConfig" />

该缓存配置类的具体实现如下:

package com.lantaiyuan.ebus.common.redis;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {

	@Bean
	public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {
		RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
		redisTemplate.setConnectionFactory(cf);
		return redisTemplate;
	}

	@Bean
	public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate) {
		RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
		cacheManager.setDefaultExpiration(3000); 
		Map<String, Long> expires = new HashMap<>();
		expires.put("nearStation", 15L);//缓存15秒
		expires.put("routeDetail", 5L);
		expires.put("cityCodes", 600L);//缓存10分钟
		expires.put("weatherInfo", 600L);//天气信息缓存10分钟
		cacheManager.setExpires(expires);
		return cacheManager;
	}

	/**
	 * 自定义key. 此方法将会根据类名+方法名+所有参数的值生成唯一的一个key,即使@Cacheable中的value属性一样,key也会不一样。
	 */
	@Override
	public KeyGenerator keyGenerator() {
		return new KeyGenerator() {
			@Override
			public Object generate(Object o, Method method, Object... objects) {
				StringBuilder sb = new StringBuilder();
				sb.append(o.getClass().getName());
				sb.append(method.getName());
				for (Object obj : objects) {
					sb.append(obj.toString());
				}
				return sb.toString();
			}
		};
	}
}

该类中定义了一个expires.put("weatherInfo", 600L)用来定义redis中缓存天气信息的命名空间,下面会用到

2. 在业务类上加缓存配置信息@CacheConfig(cacheNames="weatherInfo")

表示将该类中的缓存存储到redis中的weatherInfo域中,可理解为命名空间

@CacheConfig(cacheNames="weatherInfo")
@Service("weatherService")
public class WeatherServiceImpl implements WeatherServiceI {
…………
}

3.为该类需要添加缓存的方法加注解@Cacheable

/**
	 * 功能描述:得到聚合天气及生活指数信息
	 * 作者:温海金
	 * 最后更改时间 : 2017年4月20日 下午4:47:18
	 */
	@Cacheable
	private SeniverseWeatherAndLife getSeniverseWeather(String cityName) {
		//1.得到天气信息
		ResponseEntity<String> weatherInfo = SeniverseWeatherHelper.getSeniverseInterfaceResult(SeniverseWeatherHelper.WEATHER_URL_PRE, cityName);
		String weatherBody = weatherInfo.getBody();
		JSONObject weatherJSONObj = JSONObject.parseObject(weatherBody);
		//得到天气对象数组
		JSONArray weatherArray = weatherJSONObj.getJSONArray("results");
		//得到数组内的对象
		JSONObject weatherObject = weatherArray.getJSONObject(0);
		//得到当前天气信息对象
		JSONObject now = weatherObject.getJSONObject("now");
		SeniverseWeather seniverseWeather = JSON.parseObject(now.toJSONString(), SeniverseWeather.class);
		//2.得到生活指数
		ResponseEntity<String> lifeInfo = SeniverseWeatherHelper.getSeniverseInterfaceResult(SeniverseWeatherHelper.LIFE_URL_PRE, cityName);
		JSONObject lifeJsonObj = JSONObject.parseObject(lifeInfo.getBody());
		JSONObject lifeObject = lifeJsonObj.getJSONArray("results").getJSONObject(0);
		JSONObject suggestion = lifeObject.getJSONObject("suggestion");
		
		String flu = suggestion.getJSONObject("flu").get("brief").toString();//感冒指数
		String sport = suggestion.getJSONObject("sport").get("brief").toString();//运动指数
		String uv = suggestion.getJSONObject("uv").get("brief").toString();//紫外线
		return new SeniverseWeatherAndLife(seniverseWeather, new SeniverseLife(sport, flu, uv));
	}

这样就实现了天气信息的缓存

 

 

 

转载于:https://my.oschina.net/u/2988360/blog/883911

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值