1. 前言
先用SpringBoot搭建一个简单的单体项目,后期,再用SpringCluod把它改造一个微服务架构的项目。其实,写这篇博客的真实原因也就学习一下SpringCloud。从单体架构过渡到微服务架构,可以深刻地体会到这两者架构的区别。而且,从今后的发展来看,确实很有必要接触微服务架构
2. 数据来源
获取预报天气的数据来源:调用第三方接口进行获取。网上有很多免费的天气预报接口,随便找找就有了,也可推荐一个高德地图的天气预报接口,它只能根据城市ID获取天气信息,但它还有个接口“行政区域查询”----可以将城市名称转换为城市ID,我觉得比较麻烦,就放弃了。这里是使用了一个不知名的接口:
- 根据城市名获取天气信息:http://wthrcdn.etouch.cn/weather_mini?city=深圳
- 根据城市ID取天气信息:http://wthrcdn.etouch.cn/weather_mini?citykey=101280601
3. 实战
因为此项目是以SpringBoot为基础进行搭建的,所以,建议有SpringBoot基础的读者再看。
项目结构
项目依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
3.1 开发环境
- IDEA:2018.2(安装lombok插件)
- JDK:8
- MAVEN:3.6.0
- SpringBoot:2.3.0
3.2 功能需求
- 通过城市ID获取天气信息
- 通过城市名称获取天气信息
这两个功能可以通过调用第三方接口进行实现
3.3 手动编码
将接口返回的Json数据进行抽象、封装成Java对象,方便开发人员操作
3.3.1 vo层
WeatherResponseVO:
@Data
public class WeatherResponseVO implements Serializable {
private static final long serialVersionUID = -8483256225271502962L;
private WeatherVO data;
private Integer status;
private String desc;
}
- @Data注解:可以省略对象的set()/get()方法。@Data注解 与 lombok
- 实现Serializable 接口:因为这些Java对象要通过网络传输,所以,要序列化
WeatherVO:
@Data
public class WeatherVO implements Serializable {
private static final long serialVersionUID = 4089597935549696545L;
private String city;
private String ganmao;
private String wendu;
private YesterdayVO yesterday;
private List<ForecastVO> forecast;
}
YesterdayVO:
@Data
public class YesterdayVO implements Serializable {
private static final long serialVersionUID = -806309024676977591L;
private String date;
private String high;
private String fx;
private String low;
private String fl;
private String type;
}
ForecastVO:
@Data
public class ForecastVO implements Serializable {
private static final long serialVersionUID = 1686655601208573654L;
private String date;
private String high;
private String fengli;
private String low;
private String fengxiang;
private String type;
}
3.3.2 service层
此层是面向接口开发
WeatherDataService:
public interface WeatherDataService {
// 根据城市id查询天气数据
WeatherResponseVO getDataByCityId(String cityId);
// 根据城市名称查询天气数据
WeatherResponseVO getDataByCityName(String cityName);
}
WeatherDataServiceImpl:
@Service
public class WeatherDataServiceImpl implements WeatherDataService {
private static final String WEATHER_URL = "http://wthrcdn.etouch.cn/weather_mini?";
@Autowired
private RestTemplate restTemplate;
@Override
public WeatherResponseVO getDataByCityId(String cityId) {
String uri = WEATHER_URL + "citykey=" + cityId;
return doGetWeather(uri, WeatherResponseVO.class);
}
@Override
public WeatherResponseVO getDataByCityName(String cityName) {
String uri = WEATHER_URL + "city=" + cityName;
return doGetWeather(uri, WeatherResponseVO.class);
}
}
- 由于两个方法中都使用到了部分相同的uri,所以可以提取相同的uri作为静态常量
- RestTemplate:用于HTTP通信。使用HttpClien进行http通信,代码复杂,还得手动资源回收等。Springboot — 用更优雅的方式发HTTP请求(RestTemplate详解)
- 由于两个方法中都是通过RestTemplate进行http通信,并将返回的json数据转换为java对象,所以,便可将相同的代码进行抽取为一个共同的方法(重构)
doGetWeather():
private <T> T doGetWeather(String uri, Class<T> type) {
String key = uri;
String strBody = null;
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
if (StatusCodeConstant.OK == responseEntity.getStatusCodeValue()) {
strBody = responseEntity.getBody();
}
ObjectMapper objectMapper = new ObjectMapper();
T t = null;
try {
t = objectMapper.readValue(strBody, type);
} catch (Exception e) {
log.error("Error!", e);
}
return t;
}
- 使用了 objectMapper.readValue()方法将json字符串转换为java对象(json字符串中的key要与对象的属性名及类型相对应)
- 返回值使用了泛型
3.3.3 controller层
WeatherController:
@RestController
@RequestMapping("/weather")
public class WeatherController {
@Autowired
private WeatherDataService weatherDataService;
@GetMapping("/cityId/{cityId}")
public WeatherResponseVO getWeatherByCityId(@PathVariable("cityId") String cityId) {
return weatherDataService.getDataByCityId(cityId);
}
@GetMapping("/cityName/{cityName}")
public WeatherResponseVO getWeatherByCityName(@PathVariable("cityName") String cityName) {
return weatherDataService.getDataByCityName(cityName);
}
}
3.3.4 配置类
@Configuration
public class RestConfig {
@Autowired
private RestTemplateBuilder builder;
@Bean
public RestTemplate restTemplate() {
return builder.build();
}
}
配置RestTemplate:在启动时,RestTemplate会在classpath查找中有哪些依赖,因为已添加HttpClient依赖,所以,RestTemplate会默认把它作为默认的实现
3.3.5 测试
启动main()方法,在浏览器中访问controller层的接口
1)、根据城市ID获取天气信息
2)、根据城市名称获取天气信息
好了,这两个功能已经实现了。接下来就对它进行简单地优化了。
转载:https://blog.csdn.net/Lucky_Boy_Luck/article/details/106475477