🍳作者:天海奈奈
💭眼过千遍不如手锤一遍:推荐一款模拟面试,斩获大厂 o f f e r ,程序员的必备刷题平台 − − 牛客网
👉🏻点击开始刷题之旅
目录
2 .1.2写配置文件 创建application.properties
2.1.5 创建entity实体类,实现set /get 方法并用自动生成重写toString方法。
这个项目的功能很简单只涉及了查询功能,这个项目的的目的是熟悉SpringCloud框架,明白服务与服务之间的调用是通过http请求完成的使用微服务的架构而Feign可以使其像调用本地方法一样,学会在其他模块调用另一模块的服务和内容,完成负载均衡,学会将不同端口注册到eureka ,了解网关并会配置网关和使用断路器。
Spring Cloud Netflix Eureka
REST API、Feign、 Ribbon
Spring Cloud Netflix Zuul
Spring Cloud Netflix Hystrix
由于本项目只是为了完整的实现SpringCloud项目并明白框架功能故只设计查询功能,所以只设计两张表
表1 house

表2 
本项目是一个多模块项目,创建一个 Spring Initializr 项目 不自动添加依赖项,完成创建后删除自带的src目录,并在根目录下创建新的maven模块。
- "1.0" encoding="UTF-8"?>
"http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
-
4.0.0 -
pom -
- <module>house-servermodule>
- <module>eureak-servermodule>
- <module>house-zuulmodule>
-
-
-
org.springframework.boot -
spring-boot-starter-parent -
2.1.12.RELEASE -
-
-
com.xatu -
spring-cloud-house-test1 -
0.0.1-SNAPSHOT -
spring-cloud-house-test1 -
spring-cloud-house-test1 -
-
1.8 -
-
-
-
-
org.springframework.boot -
spring-boot-starter -
-
-
-
org.springframework.boot -
spring-boot-starter-test -
test -
-
-
-
-
-
org.springframework.cloud -
spring-cloud-dependencies -
Greenwich.SR5 -
pom -
import -
-
-
-
-
-
-
-
org.springframework.boot -
spring-boot-maven-plugin -
-
-
-

端口号 8081 url接口 /house
参数名称 :null
参数类型 : null
说明 : 找到上线房源 打印list
-
- server.port=8081
- spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
- spring.datasource.url=jdbc:mysql://localhost:3306/house_test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
- spring.datasource.username=root
- spring.datasource.password=123456
- logging.pattern.console=%clr(%d{${LOG_DATEFORMAT_PATTERN:HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}
-
- mybatis.configuration.map-underscore-to-camel-case=true
- spring.application.name=house-list
-
- eureka.client.service-url.defaultZone=http://localhost:8000/eureka/
-
-
- "1.0" encoding="UTF-8"?>
"http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
-
house-server -
com.xatu -
0.0.1-SNAPSHOT -
-
4.0.0 -
-
houser-list -
-
-
8 -
8 -
-
-
-
-
org.springframework.boot -
spring-boot-starter-web -
-
-
mysql -
mysql-connector-java -
-
-
org.mybatis.spring.boot -
mybatis-spring-boot-starter -
2.1.1 -
-
-
org.springframework.cloud -
spring-cloud-starter-netflix-eureka-client -
-
-
-
-
-
-
org.springframework.boot -
spring-boot-maven-plugin -
-
-
-
-
- /**
- * 描述: 项目启动类
- */
- @SpringBootApplication
- @EnableEurekaClient
- public class HouseListApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(HouseListApplication.class, args);
- }
- /**
- * 描述: CourseListController课程列表Controller
- */
- @RestController//将返结果是json对象
- public class HouseListController {
-
- @Autowired
- HouseListService houseListService;
-
- @GetMapping("/house")
- public List<House> houseList() {
- return houseListService.getCourseList();
- }
- }
- /**
- * 描述: House实体类
- */
- public class House implements Serializable {
-
- Integer id;
- Integer houseId;
- String houseName;
- Integer valid;
-
- @Override
- public String toString() {
- return "Course{" +
- "id=" + id +
- ", courseId=" + houseId +
- ", courseName='" + houseName + '\'' +
- ", valid=" + valid +
- '}';
- }
-
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public Integer getHouseId() {
- return houseId;
- }
-
- public void setHouseId(Integer houseId) {
- this.houseId = houseId;
- }
-
- public String getHouseName() {
- return houseName;
- }
-
- public void setHouseName(String houseName) {
- this.houseName = houseName;
- }
-
- public Integer getValid() {
- return valid;
- }
-
- public void setValid(Integer valid) {
- this.valid = valid;
- }
- }
- /**
- * 描述: 房源列表服务
- */
- public interface HouseListService {
-
- List
getCourseList(); - }
impl 实现类
- @Service
- public class HouseListServiceImpl implements HouseListService {
-
- @Autowired
- HouseMapper houseMapper;
-
-
- @Override
- public List
getCourseList() { - return houseMapper.findValidCourses();
- }
- }
mapper
- /**
- * 描述: 房源的Mapper类
- */
- @Mapper
- @Repository
- public interface HouseMapper {
-
- @Select("SELECT * FROM house WHERE valid = 1")
- List
findValidCourses(); - }
这里实现的是查询已上线的房源。

端口号 8083
url接口 /price
参数名称 :houseId
参数类型 : int
说明 : 获取到对应房源id的价格
url接口 /HouseInPrice
参数名称 :null
参数类型 : null
说明 : 作用与/list/house类似只是为了测试引入功能
url接口 /houseAndPrice
参数名称 :null
参数类型 : null
说明 : 获取到房子id 价格 id 名字
- server.port=8082
- spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
- spring.datasource.url=jdbc:mysql://localhost:3306/house_test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
- spring.datasource.username=root
- spring.datasource.password=123456
- logging.pattern.console=%clr(%d{${LOG_DATEFORMAT_PATTERN:HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}
- #tuo feng ming ming zhuan huan
- mybatis.configuration.map-underscore-to-camel-case=true
- spring.application.name=house-price
-
- eureka.client.service-url.defaultZone=http://localhost:8000/eureka/
-
- house-list.ribbon.NFLoadBanlancerRuleClassName=com.netflix.loadbalancer.RoundRobinRule
-
- feign.hystrix.enabled=true
- "1.0" encoding="UTF-8"?>
"http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
-
house-server -
com.xatu -
0.0.1-SNAPSHOT -
-
4.0.0 -
-
house-price -
-
-
8 -
8 -
-
-
-
org.springframework.boot -
spring-boot-starter-web -
-
-
mysql -
mysql-connector-java -
-
-
org.mybatis.spring.boot -
mybatis-spring-boot-starter -
2.1.1 -
-
-
org.springframework.cloud -
spring-cloud-starter-netflix-eureka-client -
-
-
org.springframework.cloud -
spring-cloud-starter-openfeign -
-
-
org.springframework.cloud -
spring-cloud-starter-netflix-hystrix -
-
-
com.xatu -
houser-list -
0.0.1-SNAPSHOT -
compile -
-
-
-
-
-
-
org.springframework.boot -
spring-boot-maven-plugin -
-
-
-
- /**
- * 描述: 项目启动类
- */
- @SpringBootApplication
- @EnableEurekaClient
- @EnableFeignClients
- @EnableCircuitBreaker
- public class HousePriceApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(HousePriceApplication.class, args);
- }
- }
- /**
- * 描述: 房源列表的Feign客户端
- */
- //当远端服务出现问题会进入这个类
- @FeignClient(value = "house-list" ,fallback = HouseListClientHystrix.class)
- //有多个实例时,带有注解的人就是注入的
- @Primary
- public interface HouseListClient {
-
- @GetMapping("/house")
- public List
houseList(); - }
如果不用feign 不同服务是不能进行调用的,我们在需要使用整合服务的模块中引入依赖 ,我加了注释了,再在启动类中加入注解,并创建一个类来作为我们引入模块的feign客户端,直接从我们想要引入的服务的controller中复制即可,引入后会有提示,要引入对另一个模块的依赖,就能数显服务的整合了。
- /**
- * 描述: 断路器实现类
- */
- @Component
- public class HouseListClientHystrix implements HouseListClient {
-
- @Override
- public List
houseList() { - List
defaultCourses = new ArrayList<>(); - House House = new House();
- House.setId(1);
- House.setHouseId(1);
- House.setHouseName("默认房源");
- House.setValid(1);
- defaultCourses.add(House);
- return defaultCourses;
- }
- }
发生错误时调用的类,给服务的返回是默认的返回值 @Component 注解使它成为一个组件
- /**
- * 描述: 房价格控制器
- */
- @RestController
- public class HousePriceController {
-
- @Autowired
- HousePriceService housePriceService;
-
- @Autowired
- HouseListClient houseListClient;
-
- @GetMapping("/price")
- public Integer getCoursePrice(Integer houseId) {
- HousePrice housePrice = housePriceService.getHousePrice(houseId);
- return housePrice.getPrice();
- }
-
- @GetMapping("/HouseInPrice")
- public List
getHouseListInPrice(Integer houseId) { - List
houses = houseListClient.houseList(); - return houses;
- }
-
- @GetMapping("/houseAndPrice")
- public List
getCoursesAndPrice() { - List
houseAndPrice = housePriceService.getHousesAndPrice(); - return houseAndPrice;
- }
-
- }
- /**
- * 描述: 房价格服务
- */
- public interface HousePriceService {
-
- HousePrice getHousePrice(Integer houseId);
-
- List
getHousesAndPrice(); - List
getHousePriceList(); - }
impl
- /**
- * 描述: 课程价格的服务实现类
- */
- @Service
- public class HousePriceServiceImpl implements HousePriceService {
-
- @Autowired
- HousePriceMapper housePriceMapper;
-
- @Autowired
- HouseListClient houseListClient;
-
- @Override
- public HousePrice getHousePrice(Integer houseId) {
- return housePriceMapper.findCoursePrice(houseId);
- }
-
- @Override
- public List
getHousesAndPrice() { - List
houseAndPricesList = new ArrayList<>(); - List
houses = houseListClient.houseList(); - for(int i = 0;i < houses.size();i++){
- House house = houses.get(i);
- if(house != null){
- HousePrice housePrice = getHousePrice(house.getHouseId());
- HouseAndPrice houseAndPrice = new HouseAndPrice();
- houseAndPrice.setPrice(housePrice.getPrice());
- houseAndPrice.setName(house.getHouseName());
- houseAndPrice.setId(house.getId());
- houseAndPrice.setHouseId(house.getHouseId());
- houseAndPricesList.add(houseAndPrice);
- }
- }
- return houseAndPricesList;
- }
-
- @Override
- public List
getHousePriceList() { -
-
- return housePriceMapper.getAll();
- }
-
-
- }
第二个方法就体现除了服务的整合,我们并不用去进行多表查询,只需要调用其他服务就能快捷完成。
- /**
- * 融合类
- *
- */
- public class HouseAndPrice {
- Integer id;
- Integer houseId;
- String name;
- Integer price;
-
- @Override
- public String toString() {
- return "HouseAndPrice{" +
- "id=" + id +
- ", houseId=" + houseId +
- ", name='" + name + '\'' +
- ", price=" + price +
- '}';
- }
-
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public Integer getHouseId() {
- return houseId;
- }
-
- public void setHouseId(Integer houseId) {
- this.houseId = houseId;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public Integer getPrice() {
- return price;
- }
-
- public void setPrice(Integer price) {
- this.price = price;
- }
- }
- public class HousePrice implements Serializable {
- Integer id;
- Integer houseId;
- Integer price;
-
- @Override
- public String toString() {
- return "HousePrice{" +
- "id=" + id +
- ", houseId=" + houseId +
- ", price=" + price +
- '}';
- }
-
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public Integer getHouseId() {
- return houseId;
- }
-
- public void setHouseId(Integer houseId) {
- this.houseId = houseId;
- }
-
- public Integer getPrice() {
- return price;
- }
-
- public void setPrice(Integer price) {
- this.price = price;
- }
- }
- /**
- * 描述: 房价格Mapper类
- */
- @Mapper
- @Repository
- public interface HousePriceMapper {
-
- @Select("SELECT * FROM house_price WHERE house_id = #{houseId}")
- HousePrice findCoursePrice(Integer courseId);
-
- @Select("SELECT * FROM house_price" )
- List
getAll(); - }
Eureka server服务注册与管理的中心 生产者,提供者
调用方:
提供者把自己的信息注册到上面,server就能掌握最新的动态,调用方去调用服务是,会先去获取最新的地址,获取地址之后再去进行实际的调用。
Eureka 开发多了获取地址这一步是对ip服务进行解耦 。
我们把强两个模块进行Eureka Client改写也很简单,只用在启动类上加注解
@EnableEurekaClient
在配置文件上进行配置
eureka.client.service-url.defaultZone=http://localhost:8000/eureka/
我们eureka端口号多少8000那项就是多少

- spring.application.name=eureka-server
- server.port=8000
- eureka.instance.hostname=localhost
- #?????
- eureka.client.fetch-registry=false
- #?????????
- eureka.client.register-with-eureka=false
- eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
第一个注释是获取注册表。不需要同步其他节点数据
第二个注释是是否发自己也注册上去
- "1.0" encoding="UTF-8"?>
"http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
-
spring-cloud-house-test1 -
com.xatu -
0.0.1-SNAPSHOT -
-
4.0.0 -
-
eureak-server -
-
-
8 -
8 -
-
course-eureka-server -
Spring Cloud Eureka -
-
-
org.springframework.cloud -
spring-cloud-starter-netflix-eureka-server -
-
-
-
-
-
-
org.springframework.boot -
spring-boot-maven-plugin -
-
-
-
- /**
- * 描述: Eureka服务端
- */
- //eurekaserver启动
- @EnableEurekaServer
- @SpringBootApplication
- public class EurekaServerApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(EurekaServerApplication.class, args);
- }
- }

这样就证明我们的服务已经注册上去了
RandomRule表示随机策略
RoundRobinRule 表示轮询策略
Response TimeWeightedRule加权,根据每一个Server的平均响应时间动态加权
其实就是在配置文件中加一行
house-list.ribbon.NFLoadBanlancerRuleClassName=com.netflix.loadbalancer.RoundRobinRuley 意思就是对house-list服务调用的时候采取的负载均衡的策略。
起到一个兜底的作用,有些时候一个服务出现问题,我们不希望整个系统都崩溃掉,那我们可以采取降级的手段,虽然不能返回正常的数据却可以保证系统正常运行。运用断路器我们不仅要配置配置文件,加依赖,还要书写一个短路类(参见price模块下client 下的断路器实现类)

- "1.0" encoding="UTF-8"?>
"http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
-
spring-cloud-house-test1 -
com.xatu -
0.0.1-SNAPSHOT -
-
4.0.0 -
-
house-zuul -
-
-
8 -
8 -
-
-
-
-
org.springframework.cloud -
spring-cloud-starter-netflix-eureka-client -
-
-
org.springframework.cloud -
spring-cloud-starter-netflix-zuul -
-
-
-
-
-
-
org.springframework.boot -
spring-boot-maven-plugin -
-
-
- spring.application.name=house-gateway
- server.port=9000
- logging.pattern.console=%clr(%d{${LOG_DATEFORMAT_PATTERN:HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}
- mybatis.configuration.map-underscore-to-camel-case=true
-
- eureka.client.service-url.defaultZone=http://localhost:8000/eureka/
-
- #???????
- zuul.prefix=/xatu
- zuul.routes.house-list.path=/list/**
- zuul.routes.house-list.service-id=house-list
- zuul.routes.house-price.path=/price/**
- zuul.routes.house-price.service-id=house-price
- /**
- * 描述: 网关启动类
- */
- //网关注解
- @EnableZuulProxy
- @SpringCloudApplication
- public class ZuulGatewayApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(ZuulGatewayApplication.class, args);
- }
- }
pre 过滤器在路由请求之前运行
route 过滤器可以处理请求的实际路由
post 路由请求后运行过滤器
error如果在处理请求的过程中发生错误,则过滤器将运行
这里写一个前置一个后置
- /**
- * 描述: 前置过滤器
- */
- @Component
- public class PreRequestFilter extends ZuulFilter {
-
- //指定过滤器类别
- @Override
- public String filterType() {
- return FilterConstants.PRE_TYPE;
- }
- //顺序
- @Override
- public int filterOrder() {
- return 5;
- }
- //是不是走过滤器可以添加判断
- @Override
- public boolean shouldFilter() {
- return true;
- }
- //通过过滤器将要实现的逻辑----打印出请求url
- @Override
- public Object run() throws ZuulException {
- RequestContext currentContext = RequestContext.getCurrentContext();
- //获取当前请求uri
- System.out.println("URI:" + currentContext.getRequest().getRequestURI());
- return null;
- }
- }
- /**
- * 描述: 后置过滤器
- */
- @Component
- public class PostRequestFilter extends ZuulFilter {
-
- @Override
- public String filterType() {
- return FilterConstants.POST_TYPE;
- }
-
- @Override
- public int filterOrder() {
- return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 1;
- }
-
- @Override
- public boolean shouldFilter() {
- return true;
- }
- //打印返回状态码
- @Override
- public Object run() throws ZuulException {
- RequestContext currentContext = RequestContext.getCurrentContext();
- int status = currentContext.getResponse().getStatus();
- System.out.println("response status:" + status);
- return null;
- }
- }
浏览器输入http://127.0.0.1:9000/xatu/house-list/house

可以看书过滤器也实现了
1 通过这个项目我们了解了SpringCloud的几个重要组件
2 数据流向
3 完成两个模块开发后进行了服务注册与发现Eureka
4 为了使服务间调用更加简便使用了Feign组件
5 使用到了负载均衡
6 使用到了熔断器
7 使用网关,并进行了过滤器的编写
---------------------------------------------------------------------------------------------------------------------------------写文不易,在这里求个三连了╥﹏╥
下次更新SpringCloud项目时会放一个功能齐全框架完整的电商项目具体上不上线等项目写完再说。