> 技术文档 > 重生之我在暑假学习微服务第九天《后端拆分部分完结篇》

重生之我在暑假学习微服务第九天《后端拆分部分完结篇》

  •  个人主页:VON
  • 文章所属专栏:微服务
  • 微服务系列文章

    重生之我在暑假学习微服务第一天《MybatisPlus-上篇》 重生之我在暑假学习微服务第二天《MybatisPlus-下篇》 重生之我在暑假学习微服务第三天《Docker-上篇》 重生之我在暑假学习微服务第四天《Docker-下篇》 重生之我在暑假学习微服务第五天《Docker部署项目篇》 重生之我在暑假学习微服务第六天《微服务之拆分项目篇》 重生之我在暑假学习微服务第七天《微服务之服务治理篇》 重生之我在暑假学习微服务第八天《OpenFeign篇》 未完待续......

    特别声明:本系列所涉及资料皆为黑马程序员课程中的资料

目录

 一、前言

二、用户部分

1、先将所用到的表导进去

2、创建user-service模块

3、改造user-service模块

(1)pom文件

(2)修改模块

(3)yaml文件

(4)测试

三、交易部分

1、创建trade-service模块

2、改造trade-service模块

(1)pom文件

(2)修改模块

(3)yaml文件

(4)改造代码 

(5)测试 

四、支付部分

1、创建pay-service模块

2、改造pay-service模块

(1)pom文件

(2)修改模块

(3)yaml文件

(4)改造代码 

(5)测试

结语


 一、前言

昨天没有更新,今天将昨天的部分也补偿上去,拆分项目所用的技术我们已经掌握的差不多了,接下来开始拆分剩下的模块。

二、用户部分

1、先将所用到的表导进去

2、创建user-service模块

还是默认直接创建就行了,创建完成后的目录是这样的

3、改造user-service模块

(1)pom文件

直接将cart-service中的拷贝过来就行了

    com.heima hm-common 1.0.0   com.heima hm-api 1.0.0    org.springframework.boot spring-boot-starter-web   org.springframework.security spring-security-rsa 1.0.9.RELEASE    mysql mysql-connector-java    com.baomidou mybatis-plus-boot-starter    com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery  

(2)修改模块

这里教大家一个小技巧,把这两个勾选上可以自动导入包

整体来看就是这么多相关的包了 ,因为屏幕限制最后一个没截图上

 

这里刚才放错位置了

准备完成后开始启动项目

(3)yaml文件

(4)测试

运行前将这里设置为local

 可以看到测试成功了

 如果报错是数据库连接超时的话就将数据库地址改一下

可以在这改

 也可以在这改

三、交易部分

交易部分和用户部分差不多

1、创建trade-service模块

还是直接默认创建即可,创建完成后将包创建出来

2、改造trade-service模块

(1)pom文件

还是和用户部分的pom文件一样

(2)修改模块

这是修改后的模块

(3)yaml文件

(4)改造代码 

扣减库存部分代码

复制下这段代码

可以看到这里爆红了,原因是没找到这个类 

直接将hm-service中的类拉过来 

 

清理购物车商品

复制这段代码

 改造完成后放在这里

 改造trade-service

这个地方需要改造下

// 3.扣减库存 try { itemClient.deductStock(detailDTOS); } catch (Exception e) { throw new RuntimeException(\"库存不足!\"); } // 4.清理购物车商品 cartClient.deleteCartItemByIds(itemIds); return order.getId();

改造后的完整代码

package com.hmall.trade.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import com.hmall.api.client.CartClient;import com.hmall.api.client.ItemClient;import com.hmall.api.dto.ItemDTO;import com.hmall.api.dto.OrderDetailDTO;import com.hmall.common.exception.BadRequestException;import com.hmall.common.utils.UserContext;import com.hmall.trade.domain.dto.OrderFormDTO;import com.hmall.trade.domain.po.Order;import com.hmall.trade.domain.po.OrderDetail;import com.hmall.trade.mapper.OrderMapper;import com.hmall.trade.service.IOrderDetailService;import com.hmall.trade.service.IOrderService;import lombok.RequiredArgsConstructor;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.Set;import java.util.stream.Collectors;/** * 

* 服务实现类 *

*/@Service@RequiredArgsConstructorpublic class OrderServiceImpl extends ServiceImpl implements IOrderService { private final ItemClient itemClient; private final IOrderDetailService detailService; private final CartClient cartClient; @Override @Transactional public Long createOrder(OrderFormDTO orderFormDTO) { // 1.订单数据 Order order = new Order(); // 1.1.查询商品 List detailDTOS = orderFormDTO.getDetails(); // 1.2.获取商品id和数量的Map Map itemNumMap = detailDTOS.stream() .collect(Collectors.toMap(OrderDetailDTO::getItemId, OrderDetailDTO::getNum)); Set itemIds = itemNumMap.keySet(); // 1.3.查询商品 List 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 details = buildDetails(order.getId(), items, itemNumMap); detailService.saveBatch(details); // 3.扣减库存 try { itemClient.deductStock(detailDTOS); } catch (Exception e) { throw new RuntimeException(\"库存不足!\"); } // 4.清理购物车商品 cartClient.deleteCartItemByIds(itemIds); return order.getId(); } private List buildDetails(Long orderId, List items, Map numMap) { List details = new ArrayList(items.size()); for (ItemDTO item : items) { OrderDetail detail = new OrderDetail(); detail.setName(item.getName()); detail.setSpec(item.getSpec()); detail.setPrice(item.getPrice()); detail.setNum(numMap.get(item.getId())); detail.setItemId(item.getId()); detail.setImage(item.getImage()); detail.setOrderId(orderId); details.add(detail); } return details; } @Override public void markOrderPaySuccess(Long orderId) { Order order = new Order(); order.setId(orderId); order.setStatus(2); // 假设 2 表示“已支付”状态 updateById(order); }}

 要将service换成Client

(5)测试 

这里在测试的时候遇到了2个问题

a-包导错了

因为包太多太乱了,所以有些蒙了,这里的所有的包都导成trade-service模块下的这点特别重要

b-又忘记nacos

错误处理完毕就可以测试了

这别忘了修改

 数据库别忘了连接

 可以看到查询到数据库中的数据了

 后台同样也有结果了

四、支付部分

1、创建pay-service模块

还是先将基础包创建出来

2、改造pay-service模块

(1)pom文件

  hmall com.heima 1.0.0  4.0.0 pay-service  11 11     com.heima hm-common 1.0.0    com.heima hm-api 1.0.0    org.springframework.boot spring-boot-starter-web    mysql mysql-connector-java    com.baomidou mybatis-plus-boot-starter    com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery    ${project.artifactId}   org.springframework.boot spring-boot-maven-plugin   

(2)修改模块

将相对应的包拉去过来

(3)yaml文件

(4)改造代码 

扣减用户余额

 新建一个接口存储用户相关的

package com.hmall.api.client;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.PutMapping;import org.springframework.web.bind.annotation.RequestParam;@FeignClient(\"user-service\")public interface UserClient { @PutMapping(\"/users/money/deduct\") void deductMoney(@RequestParam(\"pw\") String pw,@RequestParam(\"amount\") Integer amount);}

标记订单状态

 

package com.hmall.api.client;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.PutMapping;@FeignClient(\"trade-service\")public interface TradeClient { @PutMapping(\"/orders/{orderId}\") void markOrderPaySuccess(@PathVariable(\"orderId\") Long orderId);}

改造PayOrderServiceImpl

package com.hmall.pay.service.impl;import com.baomidou.mybatisplus.core.toolkit.IdWorker;import com.baomidou.mybatisplus.core.toolkit.StringUtils;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import com.hmall.api.client.TradeClient;import com.hmall.api.client.UserClient;import com.hmall.common.exception.BizIllegalException;import com.hmall.common.utils.BeanUtils;import com.hmall.common.utils.UserContext;import com.hmall.pay.domain.dto.PayApplyDTO;import com.hmall.pay.domain.dto.PayOrderFormDTO;import com.hmall.pay.domain.po.PayOrder;import com.hmall.pay.enums.PayStatus;import com.hmall.pay.mapper.PayOrderMapper;import com.hmall.pay.service.IPayOrderService;import lombok.RequiredArgsConstructor;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import java.time.LocalDateTime;/** * 

* 支付订单 服务实现类 *

* */@Service@RequiredArgsConstructorpublic class PayOrderServiceImpl extends ServiceImpl implements IPayOrderService { private final UserClient userClient; private final TradeClient tradeClient; @Override public String applyPayOrder(PayApplyDTO applyDTO) { // 1.幂等性校验 PayOrder payOrder = checkIdempotent(applyDTO); // 2.返回结果 return payOrder.getId().toString(); } @Override @Transactional public void tryPayOrderByBalance(PayOrderFormDTO payOrderDTO) { // 1.查询支付单 PayOrder po = getById(payOrderDTO.getId()); // 2.判断状态 if(!PayStatus.WAIT_BUYER_PAY.equalsValue(po.getStatus())){ // 订单不是未支付,状态异常 throw new BizIllegalException(\"交易已支付或关闭!\"); } // 3.尝试扣减余额 userClient.deductMoney(payOrderDTO.getPw(), po.getAmount()); // 4.修改支付单状态 boolean success = markPayOrderSuccess(payOrderDTO.getId(), LocalDateTime.now()); if (!success) { throw new BizIllegalException(\"交易已支付或关闭!\"); } // 5.修改订单状态 tradeClient.markOrderPaySuccess(po.getBizOrderNo()); } public boolean markPayOrderSuccess(Long id, LocalDateTime successTime) { return lambdaUpdate() .set(PayOrder::getStatus, PayStatus.TRADE_SUCCESS.getValue()) .set(PayOrder::getPaySuccessTime, successTime) .eq(PayOrder::getId, id) // 支付状态的乐观锁判断 .in(PayOrder::getStatus, PayStatus.NOT_COMMIT.getValue(), PayStatus.WAIT_BUYER_PAY.getValue()) .update(); } private PayOrder checkIdempotent(PayApplyDTO applyDTO) { // 1.首先查询支付单 PayOrder oldOrder = queryByBizOrderNo(applyDTO.getBizOrderNo()); // 2.判断是否存在 if (oldOrder == null) { // 不存在支付单,说明是第一次,写入新的支付单并返回 PayOrder payOrder = buildPayOrder(applyDTO); payOrder.setPayOrderNo(IdWorker.getId()); save(payOrder); return payOrder; } // 3.旧单已经存在,判断是否支付成功 if (PayStatus.TRADE_SUCCESS.equalsValue(oldOrder.getStatus())) { // 已经支付成功,抛出异常 throw new BizIllegalException(\"订单已经支付!\"); } // 4.旧单已经存在,判断是否已经关闭 if (PayStatus.TRADE_CLOSED.equalsValue(oldOrder.getStatus())) { // 已经关闭,抛出异常 throw new BizIllegalException(\"订单已关闭\"); } // 5.旧单已经存在,判断支付渠道是否一致 if (!StringUtils.equals(oldOrder.getPayChannelCode(), applyDTO.getPayChannelCode())) { // 支付渠道不一致,需要重置数据,然后重新申请支付单 PayOrder payOrder = buildPayOrder(applyDTO); payOrder.setId(oldOrder.getId()); payOrder.setQrCodeUrl(\"\"); updateById(payOrder); payOrder.setPayOrderNo(oldOrder.getPayOrderNo()); return payOrder; } // 6.旧单已经存在,且可能是未支付或未提交,且支付渠道一致,直接返回旧数据 return oldOrder; } private PayOrder buildPayOrder(PayApplyDTO payApplyDTO) { // 1.数据转换 PayOrder payOrder = BeanUtils.toBean(payApplyDTO, PayOrder.class); // 2.初始化数据 payOrder.setPayOverTime(LocalDateTime.now().plusMinutes(120L)); payOrder.setStatus(PayStatus.WAIT_BUYER_PAY.getValue()); payOrder.setBizUserId(UserContext.getUser()); return payOrder; } public PayOrder queryByBizOrderNo(Long bizOrderNo) { return lambdaQuery() .eq(PayOrder::getBizOrderNo, bizOrderNo) .one(); }}

(5)测试

连接下数据库

 改为local

测试成功了 

 后台也返回出了查询数据

结语

本文记录了微服务项目拆分实践过程,主要分为用户、交易和支付三个模块的改造。作者详细介绍了每个模块的创建步骤,包括pom文件配置、模块结构调整、yaml文件编写和代码改造。在用户模块实现了用户服务基础功能;交易模块重点处理了订单创建、库存扣减和购物车清理;支付模块则完成了余额扣减和订单状态更新。文章特别强调了包导入的正确性和Nacos服务注册的重要性,并分享了测试过程中遇到的数据库连接、包导入错误等问题的解决方法。通过逐步拆分和改造,最终完成了三个微服务模块的独立部署和测试。