从天气项目开始
标签: springboot api
天气接口
- 接口
http://wthrcdn.etouch.cn/weather_mini?city=滁州
http://wthrcdn.etouch.cn/weather_mini?citykey=341100
http://mobile.weather.com.cn/js/citylist.xml
接口案例
逻辑实现:实例化返回对象,通过配置httpclient进行请求发送,将返回结果通过ObjectMapper中的readValue进行反序列化。
- 实例化对象
package com.xiaojinzi.dataobject;
import lombok.Data;
import java.io.Serializable;
/**
* @author 金全 JQ
* @version 1.0 , 2018/6/3
* @description 数据返回模型
*/
@Data
public class WeatherResult implements Serializable{
/** 数据 .*/
private WeatherData data;
/** 状态码 .*/
private Integer status;
/** 描述 .*/
private String desc;
}
package com.xiaojinzi.dataobject;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* @author 金全 JQ
* @version 1.0 , 2018/6/3
* @description 天气数据
*/
@Data
public class WeatherData implements Serializable{
/** 昨日天气情况 .*/
private Yesterday yesterday;
/** 未来七日预测 .*/
private List<Forecast> forecast;
/** 城市 .*/
private String city;
/** 空气指数 .*/
private String aqi;
/** 提示 .*/
private String ganmao;
/** 温度 .*/
private String wendu;
}
package com.xiaojinzi.dataobject;
import lombok.Data;
import java.io.Serializable;
/**
* @author 金全 JQ
* @version 1.0 , 2018/6/3
* @description 昨日天气
*/
@Data
public class Yesterday implements Serializable{
/** 日期 .*/
private String date;
/** 最高温度 .*/
private String high;
/** 风向 .*/
private String fx;
/** 最低温度 .*/
private String low;
/** 风力 .*/
private String fl;
/** 天气情况 .*/
private String type;
}
package com.xiaojinzi.dataobject;
import lombok.Data;
import java.io.Serializable;
/**
* @author 金全 JQ
* @version 1.0 , 2018/6/3
* @description 天气预测
*/
@Data
public class Forecast implements Serializable {
/** 日期 .*/
private String date;
/** 最高温度 .*/
private String high;
/** 风力 .*/
private String fengli;
/** 最低温度 .*/
private String low;
/** 风向 .*/
private String fengxiang;
/** 天气情况 .*/
private String type;
}
- 反序列化
package com.xiaojinzi.services.impl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiaojinzi.config.WeatherApiConfig;
import com.xiaojinzi.dataobject.WeatherData;
import com.xiaojinzi.dataobject.WeatherResult;
import com.xiaojinzi.services.WeatherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/**
* @author 金全 JQ
* @version 1.0 , 2018/6/3
* @description
*/
@Service
public class WeatherServiceImpl implements WeatherService {
@Autowired
private WeatherApiConfig weatherApiConfig;
@Autowired
private RestTemplate restTemplate;
public WeatherResult getWeatherDataByCityName(String cityName) {
/** 连接配置 .*/
String uri = weatherApiConfig.getUrl() + "city=" + cityName;
/** 获取返回结果 .*/
ResponseEntity<String> result = restTemplate.getForEntity(uri,String.class);
/** 返回对象转换 .*/
String jsonPaser = null;
if(result.getStatusCodeValue() == 200) {
jsonPaser = result.getBody();
}else {
jsonPaser = null;
}
WeatherResult weatherResult = null;
ObjectMapper objectMapper = new ObjectMapper();
try{
/** string转换json .*/
weatherResult = objectMapper.readValue(jsonPaser,WeatherResult.class);
}catch (Exception e){
e.printStackTrace();
}
return weatherResult;
}
public WeatherResult getWeatherDataByCityId(String cityId) {
return null;
}
}
- 配置RestTemplate
package com.xiaojinzi.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @author 金全 JQ
* @version 1.0 , 2018/6/3
* @description RestTemplate配置
*/
@Configuration
public class RestTemplateConfig {
@Autowired
private RestTemplateBuilder builder;
@Bean
public RestTemplate restTemplate(){
return builder.build();
}
}
Redis提升并发访问量
windows下redis配置,下载地址。
- 配置redis启动
打开解压文件中的redis.windows.conf文件,找到 maxmemory 添加内容如下
#
# maxmemory <bytes>
maxmemory 1024000000
添加start.bat启动文件,内容如下,双击启动就行了
redis-server.exe redis.windows.conf
- 提高访问量,减少三方的服务器压力。通过设置一个内容键值队,并设置30分钟时长。
package com.xiaojinzi.services.impl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiaojinzi.config.WeatherApiConfig;
import com.xiaojinzi.dataobject.WeatherData;
import com.xiaojinzi.dataobject.WeatherResult;
import com.xiaojinzi.services.WeatherService;
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.util.concurrent.TimeUnit;
/**
* @author 金全 JQ
* @version 1.0 , 2018/6/3
* @description
*/
@Service
public class WeatherServiceImpl implements WeatherService {
@Autowired
private WeatherApiConfig weatherApiConfig;
@Autowired
private RestTemplate restTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
public WeatherResult getWeatherDataByCityName(String cityName) {
/** 连接配置 .*/
String uri = weatherApiConfig.getUrl() + "city=" + cityName;
String key = uri;
/** 返回对象转换 .*/
String jsonPaser = null;
/** 内容数据库中获值 .*/
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
/** 判断内存数据库中是否存在 .*/
if(stringRedisTemplate.hasKey(key)){
jsonPaser = ops.get(key);
}else {
/** 存储数据入库 .*/
/** 获取返回结果 .*/
ResponseEntity<String> result = restTemplate.getForEntity(uri,String.class);
if(result.getStatusCodeValue() == 200) {
jsonPaser = result.getBody();
}else {
jsonPaser = null;
}
ops.set(key,jsonPaser,weatherApiConfig.getReTimeout(), TimeUnit.SECONDS);
}
WeatherResult weatherResult = null;
ObjectMapper objectMapper = new ObjectMapper();
try{
/** string转换json .*/
weatherResult = objectMapper.readValue(jsonPaser,WeatherResult.class);
}catch (Exception e){
e.printStackTrace();
}
return weatherResult;
}
public WeatherResult getWeatherDataByCityId(String cityId) {
return null;
}
}
- 通过redis 可视化看结果
定时器quartz
通过配置定时器定时刷新获取天气,引用quartz依赖,配置定时刷新类继承QuartzJobBean类,并实例executeInternal方法。配置定时器上下文,刷新任务JobDetailBuilder,刷新方式TriggerBuilder。
- 引用
<!--定时器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
- 配置刷新类
package com.xiaojinzi.job;
import com.xiaojinzi.services.WeatherService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
/**
* @author 金全 JQ
* @version 1.0 , 2018/6/3
* @description 天气信息定时刷新
*/
@Slf4j
public class WeatherDataSyncJob extends QuartzJobBean {
@Autowired
private WeatherService weatherService;
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
weatherService.getWeatherDataByCityName("合肥");
}
}
- 配置定时器上下文
package com.xiaojinzi.config;
import com.xiaojinzi.job.WeatherDataSyncJob;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author 金全 JQ
* @version 1.0 , 2018/6/3
* @description 定时器配置
*/
@Configuration
public class QuartzConfig {
@Autowired
private WeatherApiConfig weatherApiConfig;
/**
* 定时刷新任务
* @return
*/
@Bean
public JobDetail weatherDataSyncJobDetail(){
return JobBuilder.newJob(WeatherDataSyncJob.class).withIdentity("weatherDataSyncJobDetail")
.storeDurably().build();
}
/**
* 定时刷新方式
* @return
*/
@Bean
public Trigger weatherDataSyncTrigger(){
/** 设置刷新方式 .*/
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(weatherApiConfig.getReTimeout()).repeatForever();
/** 触发器 .*/
return TriggerBuilder.newTrigger().forJob(weatherDataSyncJobDetail())
.withIdentity("weatherDataSyncTrigger").withSchedule(scheduleBuilder).build();
}
}
获取城市信息
通过读取xml文件的形式来获取城市,需将xml文件转换成obj对象,之后通过循环城市来进行城市天气信息的添加城市信息。
- xml文件内容
<?xml version="1.0" encoding="UTF-8"?>
<c c1="0">
<d d1="101220101" d2="合肥" d3="hefei" d4="安徽"/>
<d d1="101220102" d2="长丰" d3="changfeng" d4="安徽"/>
<d d1="101220103" d2="肥东" d3="feidong" d4="安徽"/>
<d d1="101220104" d2="肥西" d3="feixi" d4="安徽"/>
<d d1="101220201" d2="蚌埠" d3="bengbu" d4="安徽"/>
<d d1="101220202" d2="怀远" d3="huaiyuan" d4="安徽"/>
<d d1="101220203" d2="固镇" d3="guzhen" d4="安徽"/>
<d d1="101220204" d2="五河" d3="wuhe" d4="安徽"/>
<d d1="101220301" d2="芜湖" d3="wuhu" d4="安徽"/>
<d d1="101220302" d2="繁昌" d3="fanyang" d4="安徽"/>
<d d1="101220303" d2="芜湖县" d3="wuhuxian" d4="安徽"/>
<d d1="101220304" d2="南陵" d3="nanling" d4="安徽"/>
<d d1="101220401" d2="淮南" d3="huainan" d4="安徽"/>
<d d1="101220402" d2="凤台" d3="fengtai" d4="安徽"/>
<d d1="101220403" d2="潘集" d3="panji" d4="安徽"/>
<d d1="101220501" d2="马鞍山" d3="maanshan" d4="安徽"/>
<d d1="101220502" d2="当涂" d3="dangtu" d4="安徽"/>
<d d1="101220601" d2="安庆" d3="anqing" d4="安徽"/>
<d d1="101220602" d2="枞阳" d3="zongyang" d4="安徽"/>
<d d1="101220603" d2="太湖" d3="taihu" d4="安徽"/>
<d d1="101220604" d2="潜山" d3="qianshan" d4="安徽"/>
<d d1="101220605" d2="怀宁" d3="huaining" d4="安徽"/>
<d d1="101220606" d2="宿松" d3="susong" d4="安徽"/>
<d d1="101220607" d2="望江" d3="wangjiang" d4="安徽"/>
<d d1="101220608" d2="岳西" d3="yuexi" d4="安徽"/>
<d d1="101220609" d2="桐城" d3="tongcheng" d4="安徽"/>
<d d1="101220701" d2="宿州" d3="suzhou" d4="安徽"/>
<d d1="101220702" d2="砀山" d3="dangshan" d4="安徽"/>
<d d1="101220703" d2="灵璧" d3="lingbi" d4="安徽"/>
<d d1="101220704" d2="泗县" d3="sixian" d4="安徽"/>
<d d1="101220705" d2="萧县" d3="xiaoxian" d4="安徽"/>
<d d1="101220801" d2="阜阳" d3="fuyang" d4="安徽"/>
<d d1="101220802" d2="阜南" d3="funan" d4="安徽"/>
<d d1="101220803" d2="颍上" d3="yingshang" d4="安徽"/>
<d d1="101220804" d2="临泉" d3="linquan" d4="安徽"/>
<d d1="101220805" d2="界首" d3="jieshou" d4="安徽"/>
<d d1="101220806" d2="太和" d3="taihe" d4="安徽"/>
<d d1="101220901" d2="亳州" d3="bozhou" d4="安徽"/>
<d d1="101220902" d2="涡阳" d3="guoyang" d4="安徽"/>
<d d1="101220903" d2="利辛" d3="lixin" d4="安徽"/>
<d d1="101220904" d2="蒙城" d3="mengcheng" d4="安徽"/>
<d d1="101221001" d2="黄山" d3="huangshan" d4="安徽"/>
<d d1="101221002" d2="黄山区" d3="huangshanqu" d4="安徽"/>
<d d1="101221003" d2="屯溪" d3="tunxi" d4="安徽"/>
<d d1="101221004" d2="祁门" d3="qimen" d4="安徽"/>
<d d1="101221005" d2="黟县" d3="yixian" d4="安徽"/>
<d d1="101221006" d2="歙县" d3="shexian" d4="安徽"/>
<d d1="101221007" d2="休宁" d3="xiuning" d4="安徽"/>
<d d1="101221008" d2="黄山风景区" d3="huangshanfengjingqu" d4="安徽"/>
<d d1="101221101" d2="滁州" d3="chuzhou" d4="安徽"/>
<d d1="101221102" d2="凤阳" d3="fengyang" d4="安徽"/>
<d d1="101221103" d2="明光" d3="mingguang" d4="安徽"/>
<d d1="101221104" d2="定远" d3="dingyuan" d4="安徽"/>
<d d1="101221105" d2="全椒" d3="quanjiao" d4="安徽"/>
<d d1="101221106" d2="来安" d3="laian" d4="安徽"/>
<d d1="101221107" d2="天长" d3="tianchang" d4="安徽"/>
<d d1="101221201" d2="淮北" d3="huaibei" d4="安徽"/>
<d d1="101221202" d2="濉溪" d3="suixi" d4="安徽"/>
<d d1="101221301" d2="铜陵" d3="tongling" d4="安徽"/>
<d d1="101221401" d2="宣城" d3="xuancheng" d4="安徽"/>
<d d1="101221402" d2="泾县" d3="jingxian" d4="安徽"/>
<d d1="101221403" d2="旌德" d3="jingde" d4="安徽"/>
<d d1="101221404" d2="宁国" d3="ningguo" d4="安徽"/>
<d d1="101221405" d2="绩溪" d3="jixi" d4="安徽"/>
<d d1="101221406" d2="广德" d3="guangde" d4="安徽"/>
<d d1="101221407" d2="郎溪" d3="langxi" d4="安徽"/>
<d d1="101221501" d2="六安" d3="luan" d4="安徽"/>
<d d1="101221502" d2="霍邱" d3="huoqiu" d4="安徽"/>
<d d1="101221503" d2="寿县" d3="shouxian" d4="安徽"/>
<d d1="101221505" d2="金寨" d3="jinzhai" d4="安徽"/>
<d d1="101221506" d2="霍山" d3="huoshan" d4="安徽"/>
<d d1="101221507" d2="舒城" d3="shucheng" d4="安徽"/>
<d d1="101221601" d2="巢湖" d3="chaohu" d4="安徽"/>
<d d1="101221602" d2="庐江" d3="lujiang" d4="安徽"/>
<d d1="101221603" d2="无为" d3="wuwei" d4="安徽"/>
<d d1="101221604" d2="含山" d3="hanshan" d4="安徽"/>
<d d1="101221605" d2="和县" d3="hexian" d4="安徽"/>
<d d1="101221701" d2="池州" d3="chizhou" d4="安徽"/>
<d d1="101221702" d2="东至" d3="dongzhi" d4="安徽"/>
<d d1="101221703" d2="青阳" d3="qingyang" d4="安徽"/>
<d d1="101221704" d2="九华山" d3="jiuhuashan" d4="安徽"/>
<d d1="101221705" d2="石台" d3="shitai" d4="安徽"/>
</c>
- 实体类对应
package com.xiaojinzi.dataobject;
import lombok.Data;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
/**
* @author 金全 JQ
* @version 1.0 , 2018/6/4
* @description 城市信息
*/
@Data
@XmlRootElement(name = "d")
@XmlAccessorType(XmlAccessType.FIELD)
public class City {
/** 城市行政区代码 .*/
@XmlAttribute(name = "d1")
private String cityId;
/** 城市名称 .*/
@XmlAttribute(name = "d2")
private String cityName;
/** 城市中文拼音 .*/
@XmlAttribute(name = "d3")
private String cityNamePy;
/** 省区 .*/
@XmlAttribute(name = "d4")
private String province;
}
package com.xiaojinzi.dataobject;
import lombok.Data;
import javax.xml.bind.annotation.*;
import java.util.List;
/**
* @author 金全 JQ
* @version 1.0 , 2018/6/4
* @description 城市集合
*/
@Data
@XmlRootElement(name = "c")
@XmlAccessorType(XmlAccessType.FIELD)
public class CityList {
/** 城市结合 .*/
@XmlElement(name = "d")
private List<City> cityList;
}
- 对象转换
package com.xiaojinzi.utils;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import java.io.Reader;
import java.io.StringReader;
/**
* @author 金全 JQ
* @version 1.0 , 2018/6/4
* @description Xml对象转换
*/
public class Xml2ObjList {
/**
* 根据类及文件地址进行xml与obj进行pojo转换
* @param clazz
* @param xmlStr
* @return
* @throws Exception
*/
public static Object xml2Obj(Class<?> clazz, String xmlStr) throws Exception{
Object objXml = null;
Reader reader = null;
// XML 对象 转换
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
reader = new StringReader(xmlStr);
objXml = unmarshaller.unmarshal(reader);
// 流关闭
if(null != reader){
reader.close();
}
return objXml;
}
}
- 城市接口
package com.xiaojinzi.services.impl;
import com.xiaojinzi.dataobject.City;
import com.xiaojinzi.dataobject.CityList;
import com.xiaojinzi.services.CityDataService;
import com.xiaojinzi.utils.Xml2ObjList;
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;
/**
* @author 金全 JQ
* @version 1.0 , 2018/6/4
* @description
*/
@Service
public class CityDataServiceImpl implements CityDataService {
/**
* 城市列表获取
* @return
* @throws Exception
*/
@Override
public List<City> cityList() throws Exception {
// 获取xml
Resource resource = new ClassPathResource("citylist.xml");
BufferedReader bc = new BufferedReader(new InputStreamReader(resource.getInputStream()));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = bc.readLine())!=null){
buffer.append(line);
}
bc.close();
//xmlstr转化obj
CityList cityList = (CityList) Xml2ObjList.xml2Obj(CityList.class,buffer.toString());
return cityList.getCityList();
}
}
- 数据入库
/**
* 同步城市天气数据
* @param cityName
*/
@Override
public void weatherDataSyncByCityName(String cityName) {
/** 城市名称自动同步 .*/
String uri = weatherApiConfig.getUrl() + "city=" + cityName;
saveWeatherData(uri);
}
/**
* 存储
* @param uri
*/
private void saveWeatherData(String uri){
String key = uri;
/** 返回对象转换 .*/
String jsonPaser = null;
/** 内容数据库中获值 .*/
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
/** 存储数据入库 .*/
/** 获取返回结果 .*/
ResponseEntity<String> result = restTemplate.getForEntity(uri,String.class);
if(result.getStatusCodeValue() == 200) {
jsonPaser = result.getBody();
}else {
jsonPaser = null;
}
ops.set(key,jsonPaser,weatherApiConfig.getReTimeout(), TimeUnit.SECONDS);
}
}
集成thymeleaf模板
注入thymeleaf模板,取消模板热加载缓存,控制层前后端数据以及视图呈现。
- controller实现
package com.xiaojinzi.controller;
import com.xiaojinzi.services.CityDataService;
import com.xiaojinzi.services.WeatherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.servlet.ModelAndView;
/**
* @author 金全 JQ
* @version 1.0 , 2018/6/5
* @description 天气后台
*/
@Controller
public class WeatherReportController {
@Autowired
private WeatherService weatherService;
@Autowired
private CityDataService cityDataService;
/**
* 城市天气后台呈现
* @param cityName
* @param model
* @return
* @throws Exception
*/
@GetMapping("/report/{cityName}")
public ModelAndView weatherReportData(@PathVariable("cityName") String cityName, Model model)throws Exception{
model.addAttribute("title", "天气预报");
model.addAttribute("cityName", cityName);
model.addAttribute("cityList",cityDataService.cityList());
model.addAttribute("report", weatherService.getWeatherDataByCityName(cityName));
return new ModelAndView("weather/report","reportData",model);
}
}
- 前端呈现(thymeleaf官网)
<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>天气系统测试</title>
</head>
<body>
<h1 th:text="${reportData.title}">天气情况</h1>
<select>
<option th:each="city : ${reportData.cityList}" th:text="${city.cityName}" th:value="${city.cityName}"
th:selected="${city.cityName eq reportData.cityName}">
</option>
</select>
<div>
<p>
城市:<span th:text="${reportData.report.data.city}"></span>
空气指数:<span th:text="${reportData.report.data.aqi}"></span>
温度:<span th:text="${reportData.report.data.wendu}"></span>
友情提示:<span th:text="${reportData.report.data.ganmao}"></span>
</p>
<p>
日期:<span th:text="${reportData.report.data.yesterday.date}"></span>
</p>
<p>
最高温度:<span th:text="${reportData.report.data.yesterday.high}"></span>
最低温度:<span th:text="${reportData.report.data.yesterday.low}"></span>
风向:<span th:text="${reportData.report.data.yesterday.fx}"></span>
风力:<span th:text="${reportData.report.data.yesterday.fl}"></span>
天气情况:<span th:text="${reportData.report.data.yesterday.type}"></span>
</p>
</div>
<div th:each="forecast : ${reportData.report.data.forecast}">
<p>
日期:<span th:text="${forecast.date}"></span>
</p>
<p>
最高温度:<span th:text="${forecast.high}"></span>
最低温度:<span th:text="${forecast.low}"></span>
风向:<span th:text="${forecast.fengxiang}"></span>
风力:<span th:text="${forecast.fengli}"></span>
天气情况:<span th:text="${forecast.type}"></span>
</p>
</div>
</body>
</html>
- 本篇博客原视频博主[从天气项目观看springcloud微服务智力]
- 本篇博客撰写人: XiaoJinZi 转载请注明出处
- 学生能力有限 附上邮箱: 986209501@qq.com 不足以及误处请大佬指责