现有天气数据大而全,混杂了太多的功能,随着业务扩展,代码难以理解和维护,而且难以扩展,所以我们需要将天气预报单体项目进行拆分
对拆分也有一些需求:
- 微服务的拆分足够小,每个微服务的业务时非常单一的
- 微服务应能支持水平扩展(可以起多个未付实例)
- 如果有需要,应能实现微服务间的相互调用
下面我们来介绍一下这篇主要要写的东西:
天气预报系统的架构设计
设计分为以下几个部分:
- 天气数据采集微服务的实现
- 城市数据API微服务的实现
- 天气数据API微服务的实现
- 天气预报微服务的实现
微服务代码的拆分
系统数据流向
流向从右至左:
1、城市数据API微服务通过本地XML文件可以获取城市数据
2、天气数据采集微服务通过调用第三方接口获取天气数据,获取天气数据时根据城市ID来查询相应的天气数据,所以天气数据采集微服务也依赖于城市API数据微服务
3、采集到天气数据后存入缓存中
4、天气数据API微服务从缓存中获取到天气数据,一部分可以直接给用户使用,另外一部分传递至天气预报微服务进行展示
5、天气预报微服务展示数据时,需要根据选定的城市来向客户端展示相应的天气情况
系统的通信设计
系统存储设计
代码实现:
msa-weather-collection-server
这个微服务通过Quartz调度器和Redis同步天气数据,也就是保留原有的Quartz,对于所依赖的城市数据,通过调用城市数据微服务来获取。
msa-weather-data-server
天气查询,把查询出数据的接口暴露给用户
只对天气数据查询,不同步
public interface WeatherDataService {
/**
* 根据城市ID查询天气数据
*
* @param cityId
* @return
*/
WeatherResponse getDataByCityId(String cityId);
/**
* 根据城市名称查询天气数据
*
* @param cityName
* @return
*/
WeatherResponse getDataByCityName(String cityName);
}
msa-weather-report-server
天气预报微服务:用户通过浏览器访问天气数据,会返回相应的UI界面(设计到前端的技术)
调用天气数据微服务来提供天气数据
@Service
public class WeatherReportServiceImpl implements WeatherReportService
@Override
public Weather getDataByCityId(String cityId) {
// TODO 改为由天气数据API微服务来提供
Weather data = new Weather();
data.setApi("81");
data.setCity("深圳");
data.setGanmao("容易感冒!多穿衣");
data.setWendu("22");
List<ForeCast> forecastList = new ArrayList<>();
ForeCast forecast = new ForeCast();
forecast.setDate("25日星期天");
forecast.setType("晴");
forecast.setFengxiang("无风");
forecast.setHigh("高温 11度");
forecastList.add(forecast);
forecast = new ForeCast();
forecast.setDate("26日星期天");
forecast.setType("晴");
forecast.setFengxiang("无风");
forecast.setHigh("高温 11度");
forecastList.add(forecast);
forecast = new ForeCast();
forecast.setDate("27日星期天");
forecast.setType("晴");
forecast.setFengxiang("无风");
forecast.setHigh("高温 11度");
forecastList.add(forecast);
data.setForeCasts(forecastList);
return data;
}
}
通过调用城市数据API微服务查询出的天气数据来查询相应的天气数据
@RestController
@RequestMapping("/report")
public class WeatherReportController {
private final static Logger logger = LoggerFactory.getLogger(WeatherReportController.class);
@Autowired
private WeatherReportService weatherReportService;
@GetMapping("/cityId/{cityId}")
public ModelAndView getReportByCityId(@PathVariable("cityId") String cityId, Model model) throws Exception {
// 获取城市ID列表
// TODO 改为由城市数据API微服务来提供数据
List<City> cityList = null;
try {
// TODO 改为由城市数据API微服务提供数据
cityList = new ArrayList<>();
City city = new City();
city.setCityId("101280601");
city.setCityName("深圳");
cityList.add(city);
} catch (Exception e) {
logger.error("Exception!", e);
}
model.addAttribute("title", "老卫的天气预报");
model.addAttribute("cityId", cityId);
model.addAttribute("cityList", cityList);
model.addAttribute("report", weatherReportService.getDataByCityId(cityId));
return new ModelAndView("weather/report", "reportModel", model);
}
}
msa-weather-city-server
只查询城市数据
@Service
public class CityDataServiceImpl implements CityDataService {
@Override
public List<City> 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.xmlStrToOject(CityList.class, buffer.toString());
return cityList.getCityList();
}
}