RocketMQ 实战:模拟电商网站场景综合案例(十一)
一、RocketMQ 实战:模拟电商网站场景综合案例-- web 端项目开发
1、在 shop-order-web 工程模块中,创建 Controller 类 OrderControllre.java
/**
* shop\shop-order-web\src\main\java\com\itheima\shop\controller\OrderControllre.java
*
* 2024-6-12 创建 Controller 类 OrderControllre.java
*/
package com.itheima.shop.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.api.IOrderService;
import com.itheima.entity.Result;
import com.itheima.shop.pojo.TradeOrder;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/order")
public class OrderControllre {
@Reference
private IOrderService orderService;
@RequestMapping("/confirm")
public Result confirmOrder(@RequestBody TradeOrder order){
return orderService.confirmOrder(order);
}
}
2、在 shop-order-web 工程模块中,创建 启动 类 OrderWebApplication.java
/**
* shop\shop-order-web\src\main\java\com\itheima\shop\OrderWebApplication.java
*
* 2024-6-12 创建 启动 类 OrderWebApplication.java
*/
package com.itheima.shop;
import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableDubboConfiguration
@SpringBootApplication
public class OrderWebApplication {
public static void main(String[] args) {
SpringApplication.run(OrderWebApplication.class,args);
}
}
3、在 shop-pay-web 工程模块中,创建 Controller 类 PayController.java
/**
* shop\shop-pay-web\src\main\java\com\itheima\shop\controller\PayController.java
*
* 2024-6-12 创建 Controller 类 PayController.java
*/
package com.itheima.shop.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.api.IPayService;
import com.itheima.entity.Result;
import com.itheima.shop.pojo.TradePay;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/pay")
public class PayController {
@Reference
private IPayService payService;
@RequestMapping("/createPayment")
public Result createPayment(@RequestBody TradePay pay){
return payService.createPayment(pay);
}
@RequestMapping("/callBackPayment")
public Result callBackPayment(@RequestBody TradePay pay) throws Exception {
return payService.callbackPayment(pay);
}
}
4、在 shop-pay-web 工程模块中,创建 启动 类 PayWebApplication.java
/**
* shop\shop-pay-web\src\main\java\com\itheima\shop\PayWebApplication.java
*
* 2024-6-12 创建 启动 类 PayWebApplication.java
*/
package com.itheima.shop;
import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableDubboConfiguration
@SpringBootApplication
public class PayWebApplication {
public static void main(String[] args) {
SpringApplication.run(PayWebApplication.class,args);
}
}
二、RocketMQ 实战:模拟电商网站场景综合案例-- 整体联调:Rest 测试准备工作
1、在 shop-order-web 工程模块中,创建 配置 RestTemplate 类 RestTemplateConfig.java
/**
* shop\shop-order-web\src\main\java\com\itheima\shop\config\RestTemplateConfig.java
*
* 2024-6-12 创建 配置 RestTemplate 类 RestTemplateConfig.java
*/
package com.itheima.shop.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.List;
@Configuration
public class RestTemplateConfig {
@Bean
@ConditionalOnMissingBean({ RestOperations.class, RestTemplate.class })
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
// 使用 utf-8 编码集的 conver 替换默认的 conver(默认的 string conver 的编码集为"ISO-8859-1")
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
Iterator<HttpMessageConverter<?>> iterator = messageConverters.iterator();
while (iterator.hasNext()) {
HttpMessageConverter<?> converter = iterator.next();
if (converter instanceof StringHttpMessageConverter) {
iterator.remove();
}
}
messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
return restTemplate;
}
@Bean
@ConditionalOnMissingBean({ClientHttpRequestFactory.class})
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
// ms
factory.setReadTimeout(15000);
// ms
factory.setConnectTimeout(15000);
return factory;
}
}
2、在 shop-order-web 工程模块中,创建 application.properties 配置文件。
# shop\shop-order-web\src\main\resources\application.properties
server.host=http://localhost
server.servlet.path=/order-web
# 端口不能冲突
server.port=8080
# dubbo
spring.application.name=dubbo-order-consumer
spring.dubbo.application.id=dubbo-order-consumer
spring.dubbo.application.name=dubbo-order-consumer
spring.dubbo.registry.address=zookeeper://192.168.25.140:2181;zookeeper://192.168.25.140:2182;zookeeper://192.168.25.140:2183
order.port=8080
shop.order.baseURI=${server.host}:${order.port}${server.servlet.path}
shop.order.confirm=/order/confirm
3、在 shop-pay-web 工程模块中,创建 配置 RestTemplate 类 RestTemplateConfig.java
/**
* shop\shop-pay-web\src\main\java\com\itheima\shop\config\RestTemplateConfig.java
*
* 2024-6-12 创建 配置 RestTemplate 类 RestTemplateConfig.java
*/
package com.itheima.shop.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.List;
@Configuration
public class RestTemplateConfig {
@Bean
@ConditionalOnMissingBean({ RestOperations.class, RestTemplate.class })
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
// 使用 utf-8 编码集的 conver 替换默认的 conver(默认的 string conver 的编码集为"ISO-8859-1")
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
Iterator<HttpMessageConverter<?>> iterator = messageConverters.iterator();
while (iterator.hasNext()) {
HttpMessageConverter<?> converter = iterator.next();
if (converter instanceof StringHttpMessageConverter) {
iterator.remove();
}
}
messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
return restTemplate;
}
@Bean
@ConditionalOnMissingBean({ClientHttpRequestFactory.class})
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
// ms
factory.setReadTimeout(15000);
// ms
factory.setConnectTimeout(15000);
return factory;
}
}
4、在 shop-pay-web 工程模块中,创建 application.properties 配置文件。
# shop\shop-pay-web\src\main\resources\application.properties
server.host=http://localhost
server.servlet.path=/pay-web
# 端口不能冲突
server.port=9090
# dubbo
spring.application.name=dubbo-pay-consumer
spring.dubbo.application.id=dubbo-pay-consumer
spring.dubbo.application.name=dubbo-pay-consumer
spring.dubbo.registry.address=zookeeper://192.168.25.140:2181;zookeeper://192.168.25.140:2182;zookeeper://192.168.25.140:2183
pay.port=9090
shop.pay.baseURI=${server.host}:${pay.port}${server.servlet.path}
shop.pay.createPayment=/pay/createPayment
shop.pay.callbackPayment=/pay/callBackPayment
三、RocketMQ 实战:模拟电商网站场景综合案例-- 整体联调:Rest 方式测试下单
1、在 shop-order-web 工程模块中,创建 测试类 OrderWebTest.java
/**
* shop\shop-order-web\src\test\java\com\itheima\test\OrderWebTest.java
*
* 2024-6-12 创建 测试类 OrderWebTest.java
*/
package com.itheima.test;
import com.itheima.entity.Result;
import com.itheima.shop.OrderWebApplication;
import com.itheima.shop.pojo.TradeOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestTemplate;
import java.math.BigDecimal;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = OrderWebApplication.class)
public class OrderWebTest {
@Autowired
private RestTemplate restTemplate;
@Value("${shop.order.baseURI}")
private String baseURI;
@Value("${shop.order.confirm}")
private String confirmOrderPath;
@Test
public void confirmOrder(){
Long coupouId = 345988230098857984L;
Long goodsId = 345959443973935104L;
Long userId = 345963634385633280L;
TradeOrder order = new TradeOrder();
order.setGoodsId(goodsId);
order.setUserId(userId);
order.setCouponId(coupouId);
order.setAddress("北京");
order.setGoodsNumber(1);
order.setGoodsPrice(new BigDecimal(1000));
order.setShippingFee(BigDecimal.ZERO);
order.setOrderAmount(new BigDecimal(1000));
order.setMoneyPaid(new BigDecimal(100));
Result result = restTemplate.postForEntity(baseURI + confirmOrderPath, order, Result.class).getBody();
System.out.println(result);
}
}
2、启动各 service 工程模块的 启动类,进行测试。
四、RocketMQ 实战:模拟电商网站场景综合案例-- 整体联调:Rest 方式测试支付下单和支付回调
1、在 shop-pay-web 工程模块中,创建 测试类 PayWebTest.java
/**
* shop\shop-pay-web\src\test\java\com\itheima\test\PayWebTest.java
*
* 2024-6-12 创建 测试类 PayWebTest.java
*/
package com.itheima.test;
import com.itheima.constant.ShopCode;
import com.itheima.entity.Result;
import com.itheima.shop.PayWebApplication;
import com.itheima.shop.pojo.TradePay;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestTemplate;
import java.math.BigDecimal;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = PayWebApplication.class)
public class PayWebTest {
@Autowired
private RestTemplate restTemplate;
@Value("${shop.pay.baseURI}")
private String baseURI;
@Value("${shop.pay.createPayment}")
private String createPaymentPath;
@Value("${shop.pay.callbackPayment}")
private String callBackPaymentPath;
@Test
public void createPayment(){
long orderId = 352537369385242624L; //对应数据库中的 orderId 唯一性
TradePay tradePay = new TradePay();
tradePay.setOrderId(orderId);
tradePay.setPayAmount(new BigDecimal(880));
Result result = restTemplate.postForEntity(baseURI + createPaymentPath, tradePay, Result.class).getBody();
System.out.println(result);
}
@Test
public void callBackPayment(){
long payId = 352542415984402432L;
long orderId = 352537369385242624L;
TradePay tradePay = new TradePay();
tradePay.setPayId(payId);
tradePay.setOrderId(orderId);
tradePay.setIsPaid(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode());
Result result = restTemplate.postForEntity(baseURI + callBackPaymentPath, tradePay, Result.class).getBody();
System.out.println(result);
}
}
2、启动各 service 工程模块的 启动类,进行测试。
五、RocketMQ 实战:模拟电商网站场景综合案例-- 总结
1、案例介绍:
1.1 业务分析
1)下单业务
2)支付业务
1.2 问题分析
2、技术分析
2.1 技术选型:
1)SpringBoot
2)Dubbo
3)Zookeeper
4)RocketMQ
5)Mysql
2.2 SpringBoot 整合 RocketMQ
1)消息生产者
2)消息消费者。
2.3 SpringBoot 整合 Dubbo
1)搭建 Zookeeper 集群
2)RPC 服务接口
3)服务提供者
4)服务消费者。
3、环境搭建
3.1 数据库
1)优惠券表
2)商品表
3)订单表
4)订单商品日志表
5)用户表
6)用户余额日志表
7)订单支付表
8)MQ 消息生产表
9)MQ 消息消费表。
3.2 项目初始化
1)工程浏览
- shop-api 接口层
- shop-common 工具工程
- shop-coupon-service 优惠券服务
- shop-goods-service 商品服务
- shop-order-service 订单服务
- shop-order-web 订单系统
- shop-parent 父工程
- shop-pay-service 支付服务
- shop-pay-web 支付系统
- shop-pojo 实体类
- shop-user-service 用户服务。
- shop-dao 持久层
2)工程关系:12个系统 - shop-common 工具工程
- shop-parent 父工程
- shop-pojo 实体类
- shop-dao 持久层
- web 层 :
- shop-order-web 订单系统
- shop-pay-web 支付系统
- 接口层:shop-api 接口层
- 服务层:
- shop-coupon-service 优惠券服务
- shop-goods- 商品服务
- shop-order-service 订单服务
- shop-pay-service 支付服务
- shop-user-service 用户服务。
- 储存层:数据库 Mysql
3.3 MyBatis 逆向工程使用
1)代码生成
2)代码导入。
3.4 公共类介绍
1)ID 生成器
2)异常处理类
3)常量类
4)响应实体类。
4、下单业务
4.1 下单基本流程
- 1)接口定义
- 2)业务类实现
- 3)校验订单
- 4)生成预订单
- 5)扣减库存
- 6)扣减优惠券
- 7)扣减用户余额
- 8)确认订单
- 9)小结
4.2 失败补偿机制
- 1)消息发送方
- 2)消费接收方
4.3 测试
5、支付业务
5.1 创建支付订单
5.2 支付回调
6、整体联调
6.1 准备工作
1)配置 RestTemplate 类。
2)配置请示地址。
6.2 下单测试
6.3 支付测试。
上一节关联链接请点击:
# RocketMQ 实战:模拟电商网站场景综合案例(十)
环境搭建:数据库表结构介绍–项目工程初始化 查看 请点击:
# RocketMQ 实战:模拟电商网站场景综合案例(三)
mybatis 逆向工程 生成 POJO 类 源文件 和 mapper 映射文件 查看 请点击:
RocketMQ 实战:模拟电商网站场景综合案例(四)