目录
前言:
本文非常详细,主要讲解实际开发的代码部分,同时每个步骤都有标签,不用担心内容过长,内附详细代码。以及中途各种问题的解决方案。
springcloud案例介绍:
-
订单微服务能够查询订单信息,订单信息中包含商品数据,订单微服务要调用商品微服务完成查询
-
小案例流程图
后端部分:
1.项目结构:
分三个模块:
1.订单模块
2.商品模块
3.注册中心
2.注册中心介绍(动态识别服务器ip及端口):
1) 服务提供者将自己的IP和端口注册到注册中心上
2) 服务提供者每隔一段时间向注册中心发送心跳包
3) 服务消费者调用提供者之前,先向注册中心查询提供者的IP和端口
4) 获得服务清单中的IP和端口后,消费者调用提供者
5) 服务提供者的IP和端口改变后,通过心跳机制更新注册中心上的服务清单
3.父模块所需依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.dmdd</groupId>
<artifactId>springcloud_demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud_demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>8</java.version>
<spring.cloud-version>Hoxton.SR8</spring.cloud-version>
</properties>
<!--固定SpringCloud依赖版本-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
中途有可能会遇到 依赖无法下载的问题,点击clean,再重新启动依赖即可
4.注册中心配置:
4.1所需依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.dmdd</groupId>
<artifactId>springcloud_demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.dmdd</groupId>
<artifactId>eureka-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-service</name>
<description>eureka-service</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
该依赖需要继承父项目,如下配置,其中的内容来自于父项目依赖
<parent> <groupId>com.dmdd</groupId> <artifactId>springcloud_demo</artifactId> <version>0.0.1-SNAPSHOT</version> <relativePath/> <!-- lookup parent from repository --> </parent>父项目依赖截图
4.2.application.properties:
server.port=8000
# 服务器域名
eureka.instance.hostname=127.0.0.1
# 设置不拉取服务清单
eureka.client.fetch-registry=false
# 设置不注册当前服务
eureka.client.register-with-eureka=false
# 定义注册服务的地址
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
4.3启动类所需注解:
package com.dmdd.eurekaservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServiceApplication.class, args);
}
}
@EnableEurekaServer表示该类是注册中心服务器
order-service模块:
5.1.项目结构:
5.2所需依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.dmdd</groupId>
<artifactId>springcloud_demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.dmdd</groupId>
<artifactId>order-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>order-service</name>
<description>order-service</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
该模块也需要继承父模块。
5.3.yml配置:
server:
port: 8081
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/sys_order?serverTimezone=UTC&useUnicode=true&useSSL=false&characterEncoding=utf8&allowPublicKeyRetrieval=true
username: root
password: jly720609
application:
name: order-service
# redis:
# host: 192.168.159.128
# port: 6379
mybatis-plus:
type-aliases-package: com.blb.order_service.entity
mapper-locations: classpath:mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
cache-enabled: true
use-deprecated-executor: false
#redis缓存配置
#spring.redis.database=0
#spring.redis.jedis.pool.max-active=100
#spring.redis.jedis.pool.max-wait=100ms
#spring.redis.jedis.pool.max-idle=100
#spring.redis.jedis.pool.min-idle=10
eureka:
client:
fetch-registry: true
register-with-eureka: true
serviceUrl:
defaultZone: http://127.0.0.1:8000/eureka
eureka: client: fetch-registry: true register-with-eureka: true serviceUrl: defaultZone: http://127.0.0.1:8000/eureka实现传递动态ip和端口的配置
5.4.RestTemplateConfig:
package com.dmdd.orderservice.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
/**
* 创建RestTemplate交给容器
*/
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
服务器之间的访问主要就是靠它
订单模块访问商品模块
订单模块是服务消费者
商品模块是服务提供者
消费者模块需要配置此类
5.5.entity:
package com.dmdd.orderservice.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class SysOrder {
@TableId(type = IdType.AUTO)
private long id;
private long productId;
private long count;
private long userId;
private String time;
@TableField(exist = false)
private SysProduct product;
}
每个订单都对应一个商品。
5.6.Service核心代码:
@Override
public IPage<SysOrder> selectOrdersByPage(Long current, Long pageSize) {
Page<SysOrder> sysOrderPage = new Page<>();
sysOrderPage.setCurrent(current);
sysOrderPage.setSize(pageSize);
IPage<SysOrder> listIPage = orderMapper.listSelect(sysOrderPage);
List<SysOrder> records = listIPage.getRecords();
//获得两表连接的集合属性
for (SysOrder order : records) {
//获得每个对象的商品id
long productId = order.getProductId();
ResponseEntity<SysProduct> product = restTemplate.getForEntity("http://product-service/product/" + productId, SysProduct.class);
order.setProduct(product.getBody());
}
//将两表连接的属性赋值给它
sysOrderPage.setRecords(records);
return sysOrderPage;
}
1.通过mybatis-plus的方法查询订单表数据
2.获取每个订单的productId
3.访问商品模块的查询商品方法,通过productId查询商品信息
ResponseEntity<SysProduct> product = restTemplate.getForEntity("http://product-service/product/" + productId, SysProduct.class);
4.用订单对象存储商品对象
5.7.controller :
package com.dmdd.orderservice.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.dmdd.orderservice.entity.SysOrder;
import com.dmdd.orderservice.service.OrderService;
import com.dmdd.orderservice.util.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@CrossOrigin
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
/**
* 查询单个订单 微服务查询
*/
@GetMapping("order/{id}")
public ResponseEntity<SysOrder> selectOne(@PathVariable Long id) {
SysOrder order = orderService.getOrderById(id);
return ResponseEntity.ok(order);
}
// @GetMapping("order/{id}")
// public ResponseResult<SysOrder> selectOne(Long id) {
// SysOrder order = orderService.getOrderById(id);
// return ResponseResult.ok(order);
// }
/**
* 多表查集合
*/
@GetMapping("orders/{current}/{pageSize}")
public ResponseEntity<IPage<SysOrder>> selectOrders(@PathVariable(required = false) Long current,
@PathVariable(required = false) Long pageSize) {
IPage<SysOrder> sysOrderIPage = orderService.selectOrdersByPage(current, pageSize);
System.out.println(sysOrderIPage);
return ResponseEntity.ok(sysOrderIPage);
}
}
1.前后端分离需要配置跨域。注:商品模块无需配置此注解。因为在该案例中前端并没有直接访问商品模块。前端是通过访问订单模块,订单模块访问商品模块
@CrossOrigin2.返回参数采用
ResponseEntity
5.8启动类所需注解:
package com.dmdd.productservice;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
@MapperScan(basePackages = "com.dmdd.productservice.mapper")
public class ProductServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductServiceApplication.class, args);
}
}
@EnableDiscoveryClient表示该模块是注册中心客户端
商品模块结构:
跟订单模块没多大区别
只需要注意
1.继承父模块
2.controller层的返回参数采用
ResponseEntity
3.yml配置关于注册中心的服务器名称
4.端口号记得换,别都用一个端口号。