目录
我们本次是使用的电商项目中的商品、订单、用户为案例进行讲解。
案例准备
技术选型
maven:3.5.4
数据库:MySQL 5.7
持久层: SpingData Jpa/Mybatis-plus
其他: SpringCloud Alibaba 技术栈
模块设计
springcloud-shop父工程
shop-common 公共模块【实体类】
shop-user 用户微服务 【端口: 807x】
shop-product 商品微服务 【端口: 808x】
shop-order 订单微服务 【端口: 809x】
微服务调用
在微服务架构中,最常见的场景就是微服务之间的相互调用。我们以电商系统中常见的用户下单为 例来演示微服务的调用:客户向订单微服务发起一个下单的请求,在进行保存订单之前需要调用商品微 服务查询商品的信息。 我们一般把服务的主动调用方称为服务消费者,把服务的被调用方称为服务提供者。 在这种场景下,订单微服务就是一个服务消费者, 商品微服务就是一个服务提供者。
创建一个父工程
新工程需要更改Maven仓库地址
由于这里不需要写代码,我们将src删除
pom.xml文件中添加下面内容,锁定版本依赖
<!--依赖版本的锁定-->
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.2.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.6.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- SpringBoot 依赖配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
我们所创建的模块会继承版本,由于微服务架构是由单个单个的SpringBoot项目组合而成的,所有需要锁定版本依赖,如果版本不一致的话,在之后的项目开发中写同样的代码会出现各种各样的问题
版本对应:
https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
创建基础模块
再建一个Maven,作为我们的一个公共模块
Maven项目比SpringBoot项目的优点在于,它可以选择继承父模块
导入基础模块的依赖
<!--依赖-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
</dependencies>
可以看见,我们刚刚创建的模块自动添加了父模块
对应的父模块也自动添加了子模块
如果创建的是Maven项目的话,继承父模块是可以直接加好的,但SpringBoot项目则需要直接手动添加
创建实体类
我们在common项目中添加点代码,我们的公共模块主要就是添加一些实体类,工具包等等。
用户实体类
package com.oyang.model;
import lombok.Data;
//用户
@Data//不再去写set和get方法
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer uid;//主键
private String username;//用户名
private String password;//密码
private String telephone;//手机号
}
商品实体类
package com.oyang.model;
import lombok.Data;
//商品
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
private Integer pid;//主键
private String pname;//商品名称
private Double pprice;//商品价格
private Integer stock;//库存
}
订单实体
package com.oyang.model;
import lombok.Data;
//订单
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order {
private Long oid;//订单id
//用户
private Integer uid;//用户id
private String username;//用户名
//商品
private Integer pid;//商品id
private String pname;//商品名称
private Double pprice;//商品单价
//数量
private Integer number;//购买数量
}
由于我们要做微服务。比如用户微服务,商品微服务,订单微服务而微服务所对应的肯定有对应的实体类
创建用户微服务
步骤:
1 创建模块 导入依赖
2 创建SpringBoot主类
3 加入配置文件
4 创建必要的接口和实现类(controller service dao)
新建一个SpringBoot模块命名为shop-user ,然后进行下面操作
不用去勾选,这里版本不对应
这里是没有继承父模块的,所以我们需要自己添加。
对pom文件进行更改
只剩下两行,再添加继承父模块的代码,我们直接去common工程拷贝就行 下面的依赖也需要做出改变
<dependencies>
<!--springboot-web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入基础版块 shop-common-->
<dependency>
<groupId>com.oyang</groupId>
<artifactId>shop-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
由此可见,在基础模块里面,我们可以定义一些共用的pom依赖,比如:数据库连接、解析JSON对象、Lombok组件
由于微服务要同时启动,所以我们需要更改端口名
微服务模块设计
上面有提到
springcloud-shop父工程
shop-common 公共模块【实体类】
shop-user 用户微服务 【端口: 807x】
shop-product 商品微服务 【端口: 808x】
shop-order 订单微服务 【端口: 809x】
修改yml文件
创建商品微服务
---与用户微服务一样的操作,这里就不意义演示了
更改pom
添加下面依赖
<dependencies>
<!--springboot-web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入基础版块 shop-common-->
<dependency>
<groupId>com.oyang</groupId>
<artifactId>shop-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
更改yml文件
创建订单微服务
---与用户微服务一样的操作,这里就不意义演示了
更改pom
添加依赖
<dependencies>
<!--springboot-web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入基础版块 shop-common-->
<dependency>
<groupId>com.oyang</groupId>
<artifactId>shop-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
更改yml文件
测试微服务
我们模拟场景:订单微服务调用商品的微服务以及用户的微服务(跨项目调用功能)
用户微服务controller层
package com.oyang.shopuser.controller;
import com.oyang.model.User;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author oyang
* @site https://blog.csdn.net
* @qq 1828190940
* @create 2022-11-24 16:07
*/
@RestController
@RequestMapping("/user")
public class UserController {
//获取单个用户
@RequestMapping("/get/{id}")
public User get(@PathVariable("id") Integer id){
return new User(id,"oyang","123","15580XXXXXX");
}
}
商品微服务controller层
package com.oyang.shopproduct.controller;
import com.oyang.model.Product;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author oyang
* @site https://blog.csdn.net
* @qq 1828190940
* @create 2022-11-24 16:07
*/
@RestController
@RequestMapping("/product")
public class ProductController {
//返回商品信息
@RequestMapping("/get/{pid}")
public Product get(@PathVariable("pid") Integer pid){
return new Product(pid,"凡人修仙传",30d,30);
}
}
启动微服务
我们先测试一下能否启动项目
这里test中Junit报了错,我们直接把它删掉,因为用不到 再次启动可以看见,我们的用户微服务已经启动成功了
将商品微服务启动
在网页上测试
用户微服务
商品微服务
订单微服务调用其他微服务
微服务之间采用Restful等轻量级http协议相互调用
在启动类中添加
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
可这个需要在配置类中才有效,为什么可以加载启动类呢?
原因是启动类中@SpringBootApplication注解包含了配置类,代表当前启动类就可以当做一个配置类来使用
订单微服务controller层
package com.oyang.shoporder.controller;
import com.oyang.model.Order;
import com.oyang.model.Product;
import com.oyang.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* @author oyang
* @site https://blog.csdn.net
* @qq 1828190940
* @create 2022-11-24 16:07
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/get/{uid}/{pid}")
public Order get(@PathVariable("uid") Integer uid,@PathVariable("pid") Integer pid){
/**
* 要在订单微服务中调用 用户微服务、商品微服务--也就意味着跨项目调用
* httpClients
*/
//得到用户对象
User user = restTemplate.getForObject("http://localhost:8070/user/get/" + uid, User.class);
//得到商品对象
Product product = restTemplate.getForObject("http://localhost:8080/product/get/" + pid, Product.class);
Order order = new Order();
order.setUsername(user.getUsername());
order.setUid(user.getUid());
order.setPprice(product.getPprice());
order.setPname(product.getPname());
order.setPid(product.getPid());
order.setOid(System.currentTimeMillis());//随机生成id
order.setNumber(product.getStock());
return order;
}
}