用户服务拆分
创建数据库: 执行资料中sql文件即可
在hmall下新建一个module,命名为user-service
导入用户模块需要使用的包
<dependencies>
<!--common-->
<dependency>
<groupId>com.heima</groupId>
<artifactId>hm-common</artifactId>
<version>1.0.0</version>
</dependency>
<!--hm-api-->
<dependency>
<groupId>com.heima</groupId>
<artifactId>hm-api</artifactId>
<version>1.0.0</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--nacos 服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
添加启动类和配置文件
package com.hmall.user;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@MapperScan("com.hmall.user.mapper")
@EnableFeignClients(basePackages = "com.hmall.api.client")
@SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
server:
port: 8084 #每个微服务运行在不同端口
spring:
application:
name: user-service #每个微服务对应一个名称
cloud:
nacos:
server-addr: 192.168.1.97:8848 #nacos地址
profiles:
active: dev #读取dev的配置
datasource: #数据库配置
url: jdbc:mysql://${hm.db.host}:3306/hm-user?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: ${hm.db.pw}
mybatis-plus:
configuration:
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
global-config:
db-config:
update-strategy: not_null
id-type: auto
logging: #日志配置
level: #日志记录级别
com.hmall: debug
pattern: #日志日期格式
dateformat: HH:mm:ss:SSS
file: #日志保存目录
path: "logs/${spring.application.name}"
knife4j: #swagger配置
enable: true
openapi:
title: 黑马商城用户管理接口文档
description: "黑马商城用户管理接口文档"
email: 123456@qq.com
concat: 王
url: https://www.itcast.cn
version: v1.0.0
group:
default:
group-name: default
api-rule: package
api-rule-resources: # 指定扫描的包
- com.hmall.user.controller
登录注册代码迁移
- 项目中登录注册采用的是JWT模式
- hmall.jsk是JWT加密的密钥文件
- JwtProperties文件是读取密钥时用于封装密钥信息
- SecurityConfig文件封装了加密用户密码的方法 和 读取密钥的方法
- JwtTool文件用于生成Token和解析Token
-
在配置文件中配置密钥文件的位置信息
server:
... ...
hm:
jwt:
location: classpath:hmall.jks
alias: hmall
password: hmall123
tokenTTL: 30m
业务代码迁移
- 迁移工具类
- 迁移mapper
- 由于项目中存在多个同名类, 所以需要手动导入类文件
- 迁移service
- 迁移controller
配置启动项, 启动服务
交易服务拆分
在hmall下新建一个module,命名为trade-service
导入订单模块需要使用的包
<dependencies>
<!--common-->
<dependency>
<groupId>com.heima</groupId>
<artifactId>hm-common</artifactId>
<version>1.0.0</version>
</dependency>
<!--hm-api-->
<dependency>
<groupId>com.heima</groupId>
<artifactId>hm-api</artifactId>
<version>1.0.0</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--nacos 服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
添加启动类和配置文件
package com.hmall.trade;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@MapperScan("com.hmall.trade.mapper")
@EnableFeignClients(basePackages = "com.hmall.api.client")
@SpringBootApplication
public class TradeApplication {
public static void main(String[] args) {
SpringApplication.run(TradeApplication.class, args);
}
}
server:
port: 8085 #每个微服务运行在不同端口
spring:
application:
name: trade-service #每个微服务对应一个名称
cloud:
nacos:
server-addr: 192.168.1.97:8848 #nacos地址
profiles:
active: dev #读取dev的配置
datasource: #数据库配置
url: jdbc:mysql://${hm.db.host}:3306/hm-trade?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: ${hm.db.pw}
mybatis-plus:
configuration:
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
global-config:
db-config:
update-strategy: not_null
id-type: auto
logging: #日志配置
level: #日志记录级别
com.hmall: debug
pattern: #日志日期格式
dateformat: HH:mm:ss:SSS
file: #日志保存目录
path: "logs/${spring.application.name}"
knife4j: #swagger配置
enable: true
openapi:
title: 黑马商城交易管理接口文档
description: "黑马商城交易管理接口文档"
email: 123456@qq.com
concat: 王
url: https://www.itcast.cn
version: v1.0.0
group:
default:
group-name: default
api-rule: package
api-rule-resources: # 指定扫描的包
- com.hmall.trade.controller
业务代码迁移
- 迁移工具类
- 迁移mapper
- 迁移service
- 迁移controller
解决OrderServiceImpl报错
- 在交易服务中,用户下单时需要做下列事情:
- 根据id查询商品列表
- 计算商品总价
- 保存订单
- 扣减库存
- 清理购物车商品
- 标黑的业务需要远程调用其他服务
- 查询商品、扣减库存都是与商品有关的业务,在item-service中有相关功能;
- 清理购物车商品是购物车业务,在cart-service中有相关功能。
-
抽取ItemClient接口
@FeignClient(value = "item-service",configuration = DefaultFeignConfig.class) // 指定拉取的服务名称
public interface ItemClient {
@PutMapping("/items/stock/deduct")
void deductStock(@RequestBody List<OrderDetailDTO> items);
}
- hm-api中导入OrderDetailDTO实体类
- trade-service中删除OrderDetailDTO实体类
- trade-service中的OrderFormDTO重新导包
-
抽取CartClient接口
@FeignClient(value = "cart-service",configuration = DefaultFeignConfig.class) // 指定拉取的服务名称
public interface CartClient {@DeleteMapping("/carts") void deleteCartItemByIds(@RequestParam("ids") Collection<Long> ids);
}
-
改造OrderServiceImpl
@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {private final IOrderDetailService detailService; private final ItemClient itemClient; private final CartClient cartClient; @Override @Transactional public Long createOrder(OrderFormDTO orderFormDTO) { // 1.订单数据 Order order = new Order(); // 1.1.查询商品 List<OrderDetailDTO> detailDTOS = orderFormDTO.getDetails(); // 1.2.获取商品id和数量的Map Map<Long, Integer> itemNumMap = detailDTOS.stream() .collect(Collectors.toMap(OrderDetailDTO::getItemId, OrderDetailDTO::getNum)); Set<Long> itemIds = itemNumMap.keySet(); // 1.3.查询商品 // 改为远程调用 List<ItemDTO> items = itemClient.queryItemByIds(itemIds); if (items == null || items.size() < itemIds.size()) { throw new BadRequestException("商品不存在"); } // 1.4.基于商品价格、购买数量计算商品总价:totalFee int total = 0; for (ItemDTO item : items) { total += item.getPrice() * itemNumMap.get(item.getId()); } order.setTotalFee(total); // 1.5.其它属性 order.setPaymentType(orderFormDTO.getPaymentType()); order.setUserId(UserContext.getUser()); order.setStatus(1); // 1.6.将Order写入数据库order表中 save(order); // 2.保存订单详情 List<OrderDetail> details = buildDetails(order.getId(), items, itemNumMap); detailService.saveBatch(details); // 3.清理购物车商品 // 改为远程调用 cartClient.deleteCartItemByIds(itemIds); // 4.扣减库存 try { // 改为远程调用 itemClient.deductStock(detailDTOS); } catch (Exception e) { throw new RuntimeException("库存不足!"); } return order.getId(); }
}
-
清除重复DTO, 引入hm-api模块, 重新导包
配置启动项, 启动服务, 测试id: 1654779387523936258
支付服务拆分
新建UserCllient客户端 和 TradeClient客户端
@FeignClient("user-service")
public interface UserClient {
@PutMapping("/users/money/deduct")
void deductMoney(@RequestParam("pw") String pw, @RequestParam("amount") Integer amount);
}
@FeignClient("trade-service")
public interface TradeClient {
@PutMapping("/orders/{orderId}")
void markOrderPaySuccess(@PathVariable("orderId") Long orderId);
}
在hmall下新建一个module,命名为pay-service
导入订单模块需要使用的包
<dependencies>
<!--common-->
<dependency>
<groupId>com.heima</groupId>
<artifactId>hm-common</artifactId>
<version>1.0.0</version>
</dependency>
<!--hm-api-->
<dependency>
<groupId>com.heima</groupId>
<artifactId>hm-api</artifactId>
<version>1.0.0</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--nacos 服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
添加启动类和配置文件
package com.hmall.pay;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@MapperScan("com.hmall.pay.mapper")
@EnableFeignClients(basePackages = "com.hmall.api.client")
@SpringBootApplication
public class PayApplication {
public static void main(String[] args) {
SpringApplication.run(PayApplication.class, args);
}
}
server:
port: 8086 #每个微服务运行在不同端口
spring:
application:
name: pay-service #每个微服务对应一个名称
cloud:
nacos:
server-addr: 192.168.1.97:8848 #nacos地址
profiles:
active: dev #读取dev的配置
datasource: #数据库配置
url: jdbc:mysql://${hm.db.host}:3306/hm-pay?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: ${hm.db.pw}
mybatis-plus:
configuration:
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
global-config:
db-config:
update-strategy: not_null
id-type: auto
logging: #日志配置
level: #日志记录级别
com.hmall: debug
pattern: #日志日期格式
dateformat: HH:mm:ss:SSS
file: #日志保存目录
path: "logs/${spring.application.name}"
knife4j: #swagger配置
enable: true
openapi:
title: 黑马商城支付管理接口文档
description: "黑马商城支付管理接口文档"
email: 123456@qq.com
concat: 王
url: https://www.itcast.cn
version: v1.0.0
group:
default:
group-name: default
api-rule: package
api-rule-resources: # 指定扫描的包
- com.hmall.pay.controller
业务代码迁移
- 迁移工具类
- 迁移mapper
- 迁移service
- 迁移枚举
- 迁移controller
解决PayOrderServiceImpl报错
@Service
@RequiredArgsConstructor
public class PayOrderServiceImpl extends ServiceImpl<PayOrderMapper, PayOrder> implements IPayOrderService {
private final UserClient userClient;
private final TradeClient tradeClient;
... ...
@Override
@Transactional
public void tryPayOrderByBalance(PayOrderFormDTO payOrderFormDTO) {
// 1.查询支付单
PayOrder po = getById(payOrderFormDTO.getId());
// 2.判断状态
if(!PayStatus.WAIT_BUYER_PAY.equalsValue(po.getStatus())){
// 订单不是未支付,状态异常
throw new BizIllegalException("交易已支付或关闭!");
}
// 3.尝试扣减余额
// 远程调用
userClient.deductMoney(payOrderFormDTO.getPw(), po.getAmount());
// 4.修改支付单状态
boolean success = markPayOrderSuccess(payOrderFormDTO.getId(), LocalDateTime.now());
if (!success) {
throw new BizIllegalException("交易已支付或关闭!");
}
// 5.修改订单状态
// 远程调用
tradeClient.markOrderPaySuccess(po.getBizOrderNo());
}
... ...
}
在支付服务的PayController中添加一个接口方便测试
@ApiOperation("查询支付单")
@GetMapping
public List<PayOrderVO> queryPayOrders(){
return BeanUtils.copyList(payOrderService.list(), PayOrderVO.class);
}
配置启动项, 启动服务