创建项目
以之前的msa-weather-report-eureka-feign-gateway
为蓝本,创建msa-weather-report-eureka-feign-gateway-hystrix
项目
修改build.gradle
配置,添加Hystrix
依赖:
//依赖关系
dependencies {
//该依赖用于编译阶段
compile('org.springframework.boot:spring-boot-starter-web')
//添加Spring Boot Thymeleaf Starter的依赖
compile('org.springframework.boot:spring-boot-starter-thymeleaf')
//Eureka Client
compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client')
//Feign
compile('org.springframework.cloud:spring-cloud-starter-openfeign:2.0.0.M3')
//Hystrix
compile('org.springframework.cloud:spring-cloud-starter-netflix-hystrix')
//该依赖用于测试阶段
testCompile('org.springframework.boot:spring-boot-starter-test')
}
修改com.study.spring.cloud.weather
包下的Application
类,加入@EnableCircuitBreaker
注解:
package com.study.spring.cloud.weather;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
/*
* @SpringBootApplication注解声明Spring Boot应用
* 作用等同于@Configuration, @EnableAutoConfiguration, @ComponentScan,
* 简化Spring配置
*/
@SpringBootApplication
//启用可发现的客户端
@EnableDiscoveryClient
//启用Feign
@EnableFeignClients
//启用Hystrix
@EnableCircuitBreaker
//Application类一定要处于整个工程的根目录下,这样它才能根据配置去扫描子节点下的Spring的Bean
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
在com.study.spring.cloud.weather.service
包下新建类DataClientFallback
:
package com.study.spring.cloud.weather.service;
import com.study.spring.cloud.weather.vo.City;
import com.study.spring.cloud.weather.vo.WeatherResponse;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
//声明为Bean
@Component
public class DataClientFallback implements DataClient {
@Override
public List<City> listCity() throws Exception {
List<City> cityList=null;
cityList=new ArrayList<>();
City city=new City();
city.setCityId("101020100");
city.setCityName("上海");
cityList.add(city);
city=new City();
city.setCityId("101010100");
city.setCityName("北京");
cityList.add(city);
return cityList;
}
@Override
public WeatherResponse getDataByCityId(String cityId) {
return null;
}
}
修改com.study.spring.cloud.weather.service
包下的WeatherReportServiceImpl
类:
package com.study.spring.cloud.weather.service;
import com.study.spring.cloud.weather.vo.Weather;
import com.study.spring.cloud.weather.vo.WeatherResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class WeatherReportServiceImpl implements WeatherReportService {
@Autowired
private DataClient dataClient;
@Override
public Weather getDataByCityId(String cityId) {
//由天气数据API微服务来提供数据
WeatherResponse resp=dataClient.getDataByCityId(cityId);
Weather data=null;
if(resp!=null){
data=resp.getData();
}
return data;
}
}
修改com.study.spring.cloud.weather.service
包下的DataClient
接口:
package com.study.spring.cloud.weather.service;
import com.study.spring.cloud.weather.vo.City;
import com.study.spring.cloud.weather.vo.WeatherResponse;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
@FeignClient(name = "msa-weather-eureka-client-zuul",fallback = DataClientFallback.class)
public interface DataClient {
//获取城市列表
@GetMapping("/city/cities")
List<City> listCity() throws Exception;
//根据城市id查询天气数据
@GetMapping("/data/weather/cityId/{cityId}")
WeatherResponse getDataByCityId(@PathVariable("cityId") String cityId);
}
修改前端页面report.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<title>天气预报</title>
</head>
<body>
<div class="container">
<div class="row">
<h3 th:text="${reportModel.title}">天气</h3>
<select class="custom-select" id="selectCityId">
<option th:each="city : ${reportModel.cityList}"
th:value="${city.cityId}" th:text="${city.cityName}"
th:selected="${city.cityId eq reportModel.cityId}"></option>
</select>
</div>
<div th:if="${reportModel.report}!=null">
<div class="row">
<h1 class="text-success" th:text="${reportModel.report.city}">城市名称</h1>
</div>
<div class="row">
<p>
空气质量指数:<span th:text="${reportModel.report.aqi}"></span>
</p>
</div>
<div class="row">
<p>
当前温度:<span th:text="${reportModel.report.wendu}"></span>
</p>
</div>
<div class="row">
<p>
温馨提示:<span th:text="${reportModel.report.ganmao}"></span>
</p>
</div>
<div class="row">
<div class="card border-info" th:each="forecast : ${reportModel.report.forecast}">
<div class="card-body text-info">
<p class="card-text" th:text="${forecast.date}">日期</p>
<p class="card-text" th:text="${forecast.type}">天气类型</p>
<p class="card-text" th:text="${forecast.high}">最高温度</p>
<p class="card-text" th:text="${forecast.low}">最低温度</p>
<p class="card-text" th:text="${forecast.fengxiang}">风向</p>
</div>
</div>
</div>
</div>
<div th:if="${reportModel.report}==null">
<div class="row">
<p>
天气数据API微服务暂不可用!
</p>
</div>
</div>
</div>
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
<!-- Optional JavaScript -->
<script type="text/javascript" th:src="@{/js/weather/report.js}"></script>
</body>
</html>
修改application.properties
配置文件:
#热部署静态文件
spring.thymeleaf.cache=false
#应用名称
spring.application.name=msa-weather-report-eureka-feign-gateway-hystrix
#注册服务器的URL
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
#请求服务时的超时时间
feign.client.config.feignName.connect-timeout=5000
#读数据时的超时时间
feign.client.config.feignName.read-timeout=5000
#在feign客户端中启用断路器功能
feign.hystrix.enabled=true
运行
- 启动
Redis
- 在
IDE
上运行micro-weather-eureka-server
- 通过命令行指定
8081
和8082
端口运行msa-weather-collection-eureka-feign
- 通过命令行指定
8083
和8084
端口运行msa-weather-data-eureka
- 通过命令行指定
8085
和8086
端口运行msa-weather-city-eureka
- 通过命令行指定
8087
和8088
端口运行msa-weather-report-eureka-feign-gateway-hystrix
- 通过命令行指定
8089
端口运行msa-weather-eureka-client-zuul
访问http://localhost:8761
页面,可以看到Eureka
的管理页面:
访问http://localhost:8088/report/cityId/101020100
页面:
在页面中切换选中城市:
- 停掉
8085
和8086
两个端口的msa-weather-city-eureka
微服务
刷新http://localhost:8088/report/cityId/101020100
页面:
- 停掉
8083
和8084
两个端口的msa-weather-data-eureka
微服务
刷新http://localhost:8088/report/cityId/101020100
页面: