# RocketMQ 实战:模拟电商网站场景综合案例(三)

RocketMQ 实战:模拟电商网站场景综合案例(三)

一、环境搭建:数据库表结构介绍

1、优惠券表

FieldTypeComment
coupon_iddecigint(50) NOT NULL优惠券ID
coupon_pricedecimal(10,2) NULL优惠券金额
user idbigint(50) NULL用户ID
order idbigint(32)NULL订单ID
is usedint(1) NULL是否使用 0未使用 1已使用
used timetimestamp NULL使用时间

2、商品表

FieldTypeComment
goods idbigint(50) NOT NULL主键
goods namevarchar(255) NULL商品名称
goods numberint(11) NULL商品库存
goods_pricedecimal(10,2) NULL商品价格
goods descvarchar(255) NULL商品描述
add timetimestamp NULL添加时间

3、订单表

FieldTypeComment
order _idbigint(50) NOT NULL订单ID
user _idbigint(50) NULL用户ID
order statusint(1) NULL订单状态 0未确认 1己确认 2已取消 3无效 4退款
pay_statusint(1) NULL支付状态 0未支付 1支付中 2已支付
shipping_statusint(1) NULL发货状态 0未发货 1已发货 2已退货
addressvarchar(255) NULL收货地址
consigneevarchar(255)NULL收货人
goods idbigint(50) NULL商品ID
goods numberint(11) NULL商品数量
goods pricedecimal(10,2) NULL商品价格
goods amountdecimal(10,0) NULL商品总价
shipping_feedecimal(10,2) NULL运费
order amountdecimal(10,2) NULL订单价格
coupon_idbigint(50) NULL优惠券ID
coupon_paiddecimal(10,2) NULL优惠券
money_paiddecimal(10,2) NULL已付金额
pay_amountdecimal(10,2) NULL支付金额
add timetimestamp NULL创建时间

4、订单商品日志表

FieldTypeComment
goods idint(11) NOT NULL商品ID
order idvarchar(32) NOT NULL订单ID
goods numberint(11) NULL库存数量
log_timedatetime NULL记录时间

5、用户表

FieldTypeComment
user idbigint(50) NOT NULL用户ID
user_namevarchar(255) NULL用户姓名
user passwordvarchar(255)NULL用户密码
user mobilevarchar(255)NULL手机号
user scoreint(11)NULL积分
user_reg_timetimestamp NULL注册时间
user moneydecimal(10,0)NULL用户余额

6、用户余额日志表

FieldTypeComment
Juser idbigint(50) NOT NULL用户ID
order idbigint(50) NOT NULL订单ID
money_log_typeint(1) NOT NULL日志类型 1订单付款 2 订单退款
use moneydecimal(10,2) NULL操作金额
create timetimestamp NULL日志时间

7、订单支付表

FieldTypeComment
pay_idbigint(50) NOT NULL支付编号
order idbigint(50) NULL订单编号
pay_amountdecimal(10,2) NULL支付金额
is_paidint(1) NULL是否已支付 1否 2是

8、MQ 消息生产表

FieldTypeComment
idvarchar(100) NOT NULL主键
group _namevarchar(100) NULL生产者组名
msg_topicvarchar(100) NULL消息主题
msg_tagvarchar(100) NULLTag
msg_keyvarchar(100) NULLKey
hsg bodyvarchar(500) NULL消息内容
msg statusint(1)NULL0:未处理;1:已经处理
create timetimestamp NOT NULL记录时间

9、MQ 消息消费表

FieldTypeComment
msg_idvarchar(50) NULL消息ID
group namevarchar(100) NOT NULL消费者组名
msg_tagvarchar(100) NOT NULLTag
msg_keyvarchar(100) NOT NULLKey
msg_bodyvarchar(500) NULL消息体
consumer statusint(1) NULL0:正在处理;1:处理成功;2:处理失败
consumer timesint(1)NULL消费次数
consumer_timestamptimestamp NULL消费时间
remarkvarchar(500)NULL备注

10、在 mysql 中,创建这 9 张表。

1)用 SQLyong 连接 mysql 数据库


保存的连接:localhost  
MySQL Host Address : 如:localhost
用户名:root
密码:root
端口:3306【连接】

2)创建 trade 数据库。

3)创建 9 个 数据表。


/*
SQLyog Ultimate v8.32 
MySQL - 5.5.49 : Database - trade
*********************************************************************
*//*!40101 SET NAMES utf8 */;/*!40101 SET SQL_MODE=''*/;/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`trade` /*!40100 DEFAULT CHARACTER SET utf8 */;USE `trade`;/*Table structure for table `trade_coupon` */DROP TABLE IF EXISTS `trade_coupon`;CREATE TABLE `trade_coupon` (`coupon_id` bigint(50) NOT NULL COMMENT '优惠券ID',`coupon_price` decimal(10,2) DEFAULT NULL COMMENT '优惠券金额',`user_id` bigint(50) DEFAULT NULL COMMENT '用户ID',`order_id` bigint(32) DEFAULT NULL COMMENT '订单ID',`is_used` int(1) DEFAULT NULL COMMENT '是否使用 0未使用 1已使用',`used_time` timestamp NULL DEFAULT NULL COMMENT '使用时间',PRIMARY KEY (`coupon_id`),KEY `FK_trade_coupon` (`user_id`),KEY `FK_trade_coupon2` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;/*Data for the table `trade_coupon` *//*Table structure for table `trade_goods` */DROP TABLE IF EXISTS `trade_goods`;CREATE TABLE `trade_goods` (`goods_id` bigint(50) NOT NULL AUTO_INCREMENT,`goods_name` varchar(255) DEFAULT NULL COMMENT '商品名称',`goods_number` int(11) DEFAULT NULL COMMENT '商品库存',`goods_price` decimal(10,2) DEFAULT NULL COMMENT '商品价格',`goods_desc` varchar(255) DEFAULT NULL COMMENT '商品描述',`add_time` timestamp NULL DEFAULT NULL COMMENT '添加时间',PRIMARY KEY (`goods_id`)
) ENGINE=InnoDB AUTO_INCREMENT=345959443973935105 DEFAULT CHARSET=utf8;/*Data for the table `trade_goods` */insert  into `trade_goods`(`goods_id`,`goods_name`,`goods_number`,`goods_price`,`goods_desc`,`add_time`) values (345959443973935104,'华为P30',999,'5000.00','夜间拍照更美','2019-07-09 20:38:00');/*Table structure for table `trade_goods_number_log` */DROP TABLE IF EXISTS `trade_goods_number_log`;CREATE TABLE `trade_goods_number_log` (`goods_id` bigint(50) NOT NULL COMMENT '商品ID',`order_id` bigint(50) NOT NULL COMMENT '订单ID',`goods_number` int(11) DEFAULT NULL COMMENT '库存数量',`log_time` timestamp NULL DEFAULT NULL,PRIMARY KEY (`goods_id`,`order_id`),KEY `FK_trade_goods_number_log2` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;/*Data for the table `trade_goods_number_log` *//*Table structure for table `trade_mq_consumer_log` */DROP TABLE IF EXISTS `trade_mq_consumer_log`;CREATE TABLE `trade_mq_consumer_log` (`msg_id` varchar(50) DEFAULT NULL,`group_name` varchar(100) NOT NULL,`msg_tag` varchar(100) NOT NULL,`msg_key` varchar(100) NOT NULL,`msg_body` varchar(500) DEFAULT NULL,`consumer_status` int(1) DEFAULT NULL COMMENT '0:正在处理;1:处理成功;2:处理失败',`consumer_times` int(1) DEFAULT NULL,`consumer_timestamp` timestamp NULL DEFAULT NULL,`remark` varchar(500) DEFAULT NULL,PRIMARY KEY (`group_name`,`msg_tag`,`msg_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;/*Data for the table `trade_mq_consumer_log` *//*Table structure for table `trade_mq_producer_temp` */DROP TABLE IF EXISTS `trade_mq_producer_temp`;CREATE TABLE `trade_mq_producer_temp` (`id` varchar(100) NOT NULL,`group_name` varchar(100) DEFAULT NULL,`msg_topic` varchar(100) DEFAULT NULL,`msg_tag` varchar(100) DEFAULT NULL,`msg_key` varchar(100) DEFAULT NULL,`msg_body` varchar(500) DEFAULT NULL,`msg_status` int(1) DEFAULT NULL COMMENT '0:未处理;1:已经处理',`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;/*Data for the table `trade_mq_producer_temp` *//*Table structure for table `trade_order` */DROP TABLE IF EXISTS `trade_order`;CREATE TABLE `trade_order` (`order_id` bigint(50) NOT NULL COMMENT '订单ID',`user_id` bigint(50) DEFAULT NULL COMMENT '用户ID',`order_status` int(1) DEFAULT NULL COMMENT '订单状态 0未确认 1已确认 2已取消 3无效 4退款',`pay_status` int(1) DEFAULT NULL COMMENT '支付状态 0未支付 1支付中 2已支付',`shipping_status` int(1) DEFAULT NULL COMMENT '发货状态 0未发货 1已发货 2已收货',`address` varchar(255) DEFAULT NULL COMMENT '收货地址',`consignee` varchar(255) DEFAULT NULL COMMENT '收货人',`goods_id` bigint(50) DEFAULT NULL COMMENT '商品ID',`goods_number` int(11) DEFAULT NULL COMMENT '商品数量',`goods_price` decimal(10,2) DEFAULT NULL COMMENT '商品价格',`goods_amount` decimal(10,0) DEFAULT NULL COMMENT '商品总价',`shipping_fee` decimal(10,2) DEFAULT NULL COMMENT '运费',`order_amount` decimal(10,2) DEFAULT NULL COMMENT '订单价格',`coupon_id` bigint(50) DEFAULT NULL COMMENT '优惠券ID',`coupon_paid` decimal(10,2) DEFAULT NULL COMMENT '优惠券',`money_paid` decimal(10,2) DEFAULT NULL COMMENT '已付金额',`pay_amount` decimal(10,2) DEFAULT NULL COMMENT '支付金额',`add_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',`confirm_time` timestamp NULL DEFAULT NULL COMMENT '订单确认时间',`pay_time` timestamp NULL DEFAULT NULL COMMENT '支付时间',PRIMARY KEY (`order_id`),KEY `FK_trade_order` (`user_id`),KEY `FK_trade_order2` (`goods_id`),KEY `FK_trade_order3` (`coupon_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;/*Data for the table `trade_order` *//*Table structure for table `trade_pay` */DROP TABLE IF EXISTS `trade_pay`;CREATE TABLE `trade_pay` (`pay_id` bigint(50) NOT NULL COMMENT '支付编号',`order_id` bigint(50) DEFAULT NULL COMMENT '订单编号',`pay_amount` decimal(10,2) DEFAULT NULL COMMENT '支付金额',`is_paid` int(1) DEFAULT NULL COMMENT '是否已支付 1否 2是',PRIMARY KEY (`pay_id`),KEY `FK_trade_pay` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;/*Data for the table `trade_pay` *//*Table structure for table `trade_user` */DROP TABLE IF EXISTS `trade_user`;CREATE TABLE `trade_user` (`user_id` bigint(50) NOT NULL AUTO_INCREMENT COMMENT '用户ID',`user_name` varchar(255) DEFAULT NULL COMMENT '用户姓名',`user_password` varchar(255) DEFAULT NULL COMMENT '用户密码',`user_mobile` varchar(255) DEFAULT NULL COMMENT '手机号',`user_score` int(11) DEFAULT NULL COMMENT '积分',`user_reg_time` timestamp NULL DEFAULT NULL COMMENT '注册时间',`user_money` decimal(10,0) DEFAULT NULL COMMENT '用户余额',PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=345963634385633281 DEFAULT CHARSET=utf8;/*Data for the table `trade_user` */insert  into `trade_user`(`user_id`,`user_name`,`user_password`,`user_mobile`,`user_score`,`user_reg_time`,`user_money`) values (345963634385633280,'刘备','123L','18888888888L',100,'2019-07-09 13:37:03','900');/*Table structure for table `trade_user_money_log` */DROP TABLE IF EXISTS `trade_user_money_log`;CREATE TABLE `trade_user_money_log` (`user_id` bigint(50) NOT NULL COMMENT '用户ID',`order_id` bigint(50) NOT NULL COMMENT '订单ID',`money_log_type` int(1) NOT NULL COMMENT '日志类型 1订单付款 2 订单退款',`use_money` decimal(10,2) DEFAULT NULL,`create_time` timestamp NULL DEFAULT NULL COMMENT '日志时间',PRIMARY KEY (`user_id`,`order_id`,`money_log_type`),KEY `FK_trade_user_money_log2` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;/*Data for the table `trade_user_money_log` *//*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

二、项目工程初始化

1、创建 shop-parent 父工程,并在 pom.xml 中,导入依赖坐标。


<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.iteima.shop</groupId><artifactId>shop-parent</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.1.RELEASE</version></parent><properties><rocketmq-spring-boot-starter-version>2.0.3</rocketmq-spring-boot-starter-version></properties><dependencies><!--dubbo--><dependency><groupId>com.alibaba.spring.boot</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.0.0</version></dependency><!--spring-boot-stater--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><artifactId>log4j-to-slf4j</artifactId><groupId>org.apache.logging.log4j</groupId></exclusion></exclusions></dependency><!--zookeeper--><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.10</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion><exclusion><groupId>log4j</groupId><artifactId>log4j</artifactId></exclusion></exclusions></dependency><dependency><groupId>com.101tec</groupId><artifactId>zkclient</artifactId><version>0.9</version><exclusions><exclusion><artifactId>slf4j-log4j12</artifactId><groupId>org.slf4j</groupId></exclusion></exclusions></dependency><!--Test--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId></dependency><!--RocketMQ--><dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>${rocketmq-spring-boot-starter-version}</version></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.6</version></dependency></dependencies><modules><module>../shop-order-web</module><module>../shop-coupon-service</module><module>../shop-user-service</module><module>../shop-order-service</module><module>../shop-pay-web</module><module>../shop-pojo</module><module>../shop-common</module><module>../shop-api</module><module>../shop-goods-service</module><module>../shop-pay-service</module></modules><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.7.0</version><configuration><target>1.8</target><source>1.8</source></configuration></plugin></plugins></build></project>
<!-- D:\java-test\idea2019\shop\shop-parent\pom.xml -->

2、创建 shop-api 接口层 工程。

2.1、在 pom.xml 中,导入依赖坐标。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>shop-parent</artifactId><groupId>com.iteima.shop</groupId><version>1.0-SNAPSHOT</version><relativePath>../shop-parent/pom.xml</relativePath></parent><modelVersion>4.0.0</modelVersion><artifactId>shop-api</artifactId><dependencies><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-pojo</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
<!-- D:\java-test\idea2019\shop\shop-api\pom.xml -->
2.2、创建 优惠券接口 类 ICouponService.java
package com.itheima.api;import com.itheima.entity.Result;
import com.itheima.shop.pojo.TradeCoupon;/*** 优惠券接口*/
public interface ICouponService {/*** 根据ID查询优惠券对象* @param coupouId* @return*/public TradeCoupon findOne(Long coupouId);/*** 更细优惠券状态* @param coupon* @return*/Result updateCouponStatus(TradeCoupon coupon);
}
2.3、创建 接口 类 IGoodsService.java
package com.itheima.api;import com.itheima.entity.Result;
import com.itheima.shop.pojo.TradeGoods;
import com.itheima.shop.pojo.TradeGoodsNumberLog;public interface IGoodsService {/*** 根据ID查询商品对象* @param goodsId* @return*/TradeGoods findOne(Long goodsId);/*** 扣减库存* @param goodsNumberLog* @return*/Result reduceGoodsNum(TradeGoodsNumberLog goodsNumberLog);
}
2.4、创建 接口 类 IOrderService.java
package com.itheima.api;import com.itheima.entity.Result;
import com.itheima.shop.pojo.TradeOrder;public interface IOrderService {/*** 下单接口* @param order* @return*/public Result confirmOrder(TradeOrder order);}
2.5、创建 接口 类 IPayService.java
package com.itheima.api;import com.itheima.entity.Result;
import com.itheima.shop.pojo.TradePay;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.remoting.exception.RemotingException;public interface IPayService {public Result createPayment(TradePay tradePay);public Result callbackPayment(TradePay tradePay) throws InterruptedException, RemotingException, MQClientException, MQBrokerException;}
2.6、创建 接口 类 IUserService.java
package com.itheima.api;import com.itheima.entity.Result;
import com.itheima.shop.pojo.TradeUser;
import com.itheima.shop.pojo.TradeUserMoneyLog;public interface IUserService {TradeUser findOne(Long userId);Result updateMoneyPaid(TradeUserMoneyLog userMoneyLog);
}

3、创建 shop-common 工具工程。

3.1、在 pom.xml 中,导入依赖坐标。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>shop-parent</artifactId><groupId>com.iteima.shop</groupId><version>1.0-SNAPSHOT</version><relativePath>../shop-parent/pom.xml</relativePath></parent><modelVersion>4.0.0</modelVersion><artifactId>shop-common</artifactId></project>
<!-- D:\java-test\idea2019\shop\shop-common\pom.xml -->
3.2、创建 类 ShopCode.java
package com.itheima.constant;/*** @author Think*/public enum ShopCode {//正确SHOP_SUCCESS(true, 1, "正确"),//错误SHOP_FAIL(false, 0, "错误"),//付款SHOP_USER_MONEY_PAID(true, 1, "付款"),//退款SHOP_USER_MONEY_REFUND(true, 2, "退款"),//订单未确认SHOP_ORDER_NO_CONFIRM(false, 0, "订单未确认"),//订单已确认SHOP_ORDER_CONFIRM(true, 1, "订单已经确认"),//订单已取消SHOP_ORDER_CANCEL(false, 2, "订单已取消"),//订单已取消SHOP_ORDER_INVALID(false, 3, "订单无效"),//订单已取消SHOP_ORDER_RETURNED(false, 4, "订单已退货"),//订单已付款SHOP_ORDER_PAY_STATUS_NO_PAY(true,0,"订单未付款"),//订单已付款SHOP_ORDER_PAY_STATUS_PAYING(true,1,"订单正在付款"),//订单已付款SHOP_ORDER_PAY_STATUS_IS_PAY(true,2,"订单已付款"),//消息正在处理SHOP_MQ_MESSAGE_STATUS_PROCESSING(true, 0, "消息正在处理"),//消息处理成功SHOP_MQ_MESSAGE_STATUS_SUCCESS(true, 1, "消息处理成功"),//消息处理失败SHOP_MQ_MESSAGE_STATUS_FAIL(false, 2, "消息处理失败"),//请求参数有误SHOP_REQUEST_PARAMETER_VALID(false, -1, "请求参数有误"),//优惠券已经使用SHOP_COUPON_ISUSED(true, 1, "优惠券已经使用"),//优惠券未使用SHOP_COUPON_UNUSED(false, 0, "优惠券未使用"),//快递运费不正确SHOP_ORDER_STATUS_UPDATE_FAIL(false, 10001, "订单状态修改失败"),//快递运费不正确SHOP_ORDER_SHIPPINGFEE_INVALID(false, 10002, "订单运费不正确"),//订单总价格不合法SHOP_ORDERAMOUNT_INVALID(false, 10003, "订单总价格不正确"),//订单保存失败SHOP_ORDER_SAVE_ERROR(false, 10004, "订单保存失败"),//订单确认失败SHOP_ORDER_CONFIRM_FAIL(false, 10005, "订单确认失败"),//商品不存在SHOP_GOODS_NO_EXIST(false, 20001, "商品不存在"),//订单价格非法SHOP_GOODS_PRICE_INVALID(false, 20002, "商品价格非法"),//商品库存不足SHOP_GOODS_NUM_NOT_ENOUGH(false, 20003, "商品库存不足"),//扣减库存失败SHOP_REDUCE_GOODS_NUM_FAIL(false, 20004, "扣减库存失败"),//库存记录为空SHOP_REDUCE_GOODS_NUM_EMPTY(false, 20005, "扣减库存失败"),//用户账号不能为空SHOP_USER_IS_NULL(false, 30001, "用户账号不能为空"),//用户信息不存在SHOP_USER_NO_EXIST(false, 30002, "用户不存在"),//余额扣减失败SHOP_USER_MONEY_REDUCE_FAIL(false, 30003, "余额扣减失败"),//已经退款SHOP_USER_MONEY_REFUND_ALREADY(true, 30004, "订单已经退过款"),//优惠券不不存在SHOP_COUPON_NO_EXIST(false, 40001, "优惠券不存在"),//优惠券不合法SHOP_COUPON_INVALIED(false, 40002, "优惠券不合法"),//优惠券使用失败SHOP_COUPON_USE_FAIL(false, 40003, "优惠券使用失败"),//余额不能小于0SHOP_MONEY_PAID_LESS_ZERO(false, 50001, "余额不能小于0"),//余额非法SHOP_MONEY_PAID_INVALID(false, 50002, "余额非法"),//Topic不能为空SHOP_MQ_TOPIC_IS_EMPTY(false, 60001, "Topic不能为空"),//消息体不能为空SHOP_MQ_MESSAGE_BODY_IS_EMPTY(false, 60002, "消息体不能为空"),//消息发送失败SHOP_MQ_SEND_MESSAGE_FAIL(false,60003,"消息发送失败"),//支付订单未找到SHOP_PAYMENT_NOT_FOUND(false,70001,"支付订单未找到"),//支付订单已支付SHOP_PAYMENT_IS_PAID(false,70002,"支付订单已支付"),//订单付款失败SHOP_PAYMENT_PAY_ERROR(false,70002,"订单支付失败");Boolean success;Integer code;String message;ShopCode() {}ShopCode(Boolean success, Integer code, String message) {this.success = success;this.code = code;this.message = message;}public Boolean getSuccess() {return success;}public void setSuccess(Boolean success) {this.success = success;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}@Overridepublic String toString() {return "ShopCode{" +"success=" + success +", code=" + code +", message='" + message + '\'' +'}';}
}
3.3、创建 类 CastException.java
package com.itheima.exception;import com.itheima.constant.ShopCode;
import lombok.extern.slf4j.Slf4j;/*** 异常抛出类*/
@Slf4j
public class CastException {public static void cast(ShopCode shopCode) {log.error(shopCode.toString());throw new CustomerException(shopCode);}
}
3.4、创建 类 CustomerException.java
package com.itheima.exception;import com.itheima.constant.ShopCode;/*** 自定义异常*/
public class CustomerException extends RuntimeException{private ShopCode shopCode;public CustomerException(ShopCode shopCode) {this.shopCode = shopCode;}
}
3.5、创建 类 IDWorker.java
package com.itheima.utils;public class IDWorker {/*** 起始的时间戳*/private final static long START_STMP = 1480166465631L;/*** 每一部分占用的位数*/private final static long SEQUENCE_BIT = 12; //序列号占用的位数private final static long MACHINE_BIT = 5;   //机器标识占用的位数private final static long DATACENTER_BIT = 5;//数据中心占用的位数/*** 每一部分的最大值*/private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);/*** 每一部分向左的位移*/private final static long MACHINE_LEFT = SEQUENCE_BIT;private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;private long datacenterId;  //数据中心private long machineId;     //机器标识private long sequence = 0L; //序列号private long lastStmp = -1L;//上一次时间戳public IDWorker(long datacenterId, long machineId) {if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");}if (machineId > MAX_MACHINE_NUM || machineId < 0) {throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");}this.datacenterId = datacenterId;this.machineId = machineId;}/*** 产生下一个ID** @return*/public synchronized long nextId() {long currStmp = getNewstmp();if (currStmp < lastStmp) {throw new RuntimeException("Clock moved backwards.  Refusing to generate id");}if (currStmp == lastStmp) {//相同毫秒内,序列号自增sequence = (sequence + 1) & MAX_SEQUENCE;//同一毫秒的序列数已经达到最大if (sequence == 0L) {currStmp = getNextMill();}} else {//不同毫秒内,序列号置为0sequence = 0L;}lastStmp = currStmp;return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分| datacenterId << DATACENTER_LEFT       //数据中心部分| machineId << MACHINE_LEFT             //机器标识部分| sequence;                             //序列号部分}private long getNextMill() {long mill = getNewstmp();while (mill <= lastStmp) {mill = getNewstmp();}return mill;}private long getNewstmp() {return System.currentTimeMillis();}public static void main(String[] args) {IDWorker idWorker = new IDWorker(2, 3);for (int i = 0; i < 10; i++) {System.out.println(idWorker.nextId());}}}

4、创建 shop-coupon-service 优惠券服务 工程。

4.1、在 pom.xml 中,导入依赖坐标。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>shop-parent</artifactId><groupId>com.iteima.shop</groupId><version>1.0-SNAPSHOT</version><relativePath>../shop-parent/pom.xml</relativePath></parent><modelVersion>4.0.0</modelVersion><artifactId>shop-coupon-service</artifactId><dependencies><!--mybatis-springboot--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.1</version></dependency><!-- MySQL连接驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-api</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-common</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-pojo</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
<!-- D:\java-test\idea2019\shop\shop-coupon-service\pom.xml -->
4.2 创建 类 TradeCouponMapper.java
package com.itheima.shop.mapper;import com.itheima.shop.pojo.TradeCoupon;
import com.itheima.shop.pojo.TradeCouponExample;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper
public interface TradeCouponMapper {int countByExample(TradeCouponExample example);int deleteByExample(TradeCouponExample example);int deleteByPrimaryKey(Long couponId);int insert(TradeCoupon record);int insertSelective(TradeCoupon record);List<TradeCoupon> selectByExample(TradeCouponExample example);TradeCoupon selectByPrimaryKey(Long couponId);int updateByExampleSelective(@Param("record") TradeCoupon record, @Param("example") TradeCouponExample example);int updateByExample(@Param("record") TradeCoupon record, @Param("example") TradeCouponExample example);int updateByPrimaryKeySelective(TradeCoupon record);int updateByPrimaryKey(TradeCoupon record);
}
4.3 创建 类 CancelMQListener.java
package com.itheima.shop.mq;import com.alibaba.fastjson.JSON;
import com.itheima.constant.ShopCode;
import com.itheima.entity.MQEntity;
import com.itheima.shop.mapper.TradeCouponMapper;
import com.itheima.shop.pojo.TradeCoupon;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.io.UnsupportedEncodingException;@Slf4j
@Component
@RocketMQMessageListener(topic = "${mq.order.topic}", consumerGroup = "${mq.order.consumer.group.name}", messageModel = MessageModel.BROADCASTING)
public class CancelMQListener implements RocketMQListener<MessageExt> {@Autowiredprivate TradeCouponMapper couponMapper;@Overridepublic void onMessage(MessageExt message) {try {//1. 解析消息内容String body = new String(message.getBody(), "UTF-8");MQEntity mqEntity = JSON.parseObject(body, MQEntity.class);log.info("接收到消息");if(mqEntity.getCouponId()!=null){//2. 查询优惠券信息TradeCoupon coupon = couponMapper.selectByPrimaryKey(mqEntity.getCouponId());//3.更改优惠券状态coupon.setUsedTime(null);coupon.setIsUsed(ShopCode.SHOP_COUPON_UNUSED.getCode());coupon.setOrderId(null);couponMapper.updateByPrimaryKey(coupon);}log.info("回退优惠券成功");} catch (UnsupportedEncodingException e) {e.printStackTrace();log.error("回退优惠券失败");}}
}
4.4 创建 类 CouponServiceImpl.java
package com.itheima.shop.service.impl;import com.alibaba.dubbo.config.annotation.Service;
import com.itheima.api.ICouponService;
import com.itheima.constant.ShopCode;
import com.itheima.entity.Result;
import com.itheima.exception.CastException;
import com.itheima.shop.mapper.TradeCouponMapper;
import com.itheima.shop.pojo.TradeCoupon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
@Service(interfaceClass = ICouponService.class)
public class CouponServiceImpl implements ICouponService{@Autowiredprivate TradeCouponMapper couponMapper;@Overridepublic TradeCoupon findOne(Long coupouId) {if(coupouId==null){CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);}return couponMapper.selectByPrimaryKey(coupouId);}@Overridepublic Result updateCouponStatus(TradeCoupon coupon) {if(coupon==null||coupon.getCouponId()==null){CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);}//更新优惠券状态couponMapper.updateByPrimaryKey(coupon);return new Result(ShopCode.SHOP_SUCCESS.getSuccess(),ShopCode.SHOP_SUCCESS.getMessage());}
}
4.5 创建 类 CouponServiceApplication.java
package com.itheima.shop;import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@EnableDubboConfiguration
public class CouponServiceApplication {public static void main(String[] args) {SpringApplication.run(CouponServiceApplication.class,args);}}
4.6 创建 TradeCouponMapper.xml 文件。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.itheima.shop.mapper.TradeCouponMapper" ><resultMap id="BaseResultMap" type="com.itheima.shop.pojo.TradeCoupon" ><id column="coupon_id" property="couponId" jdbcType="BIGINT" /><result column="coupon_price" property="couponPrice" jdbcType="DECIMAL" /><result column="user_id" property="userId" jdbcType="BIGINT" /><result column="order_id" property="orderId" jdbcType="BIGINT" /><result column="is_used" property="isUsed" jdbcType="INTEGER" /><result column="used_time" property="usedTime" jdbcType="TIMESTAMP" /></resultMap><sql id="Example_Where_Clause" ><where ><foreach collection="oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Update_By_Example_Where_Clause" ><where ><foreach collection="example.oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Base_Column_List" >coupon_id, coupon_price, user_id, order_id, is_used, used_time</sql><select id="selectByExample" resultMap="BaseResultMap" parameterType="com.itheima.shop.pojo.TradeCouponExample" >select<if test="distinct" >distinct</if><include refid="Base_Column_List" />from trade_coupon<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if><if test="orderByClause != null" >order by ${orderByClause}</if></select><select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >select <include refid="Base_Column_List" />from trade_couponwhere coupon_id = #{couponId,jdbcType=BIGINT}</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Long" >delete from trade_couponwhere coupon_id = #{couponId,jdbcType=BIGINT}</delete><delete id="deleteByExample" parameterType="com.itheima.shop.pojo.TradeCouponExample" >delete from trade_coupon<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></delete><insert id="insert" parameterType="com.itheima.shop.pojo.TradeCoupon" >insert into trade_coupon (coupon_id, coupon_price, user_id, order_id, is_used, used_time)values (#{couponId,jdbcType=BIGINT}, #{couponPrice,jdbcType=DECIMAL}, #{userId,jdbcType=BIGINT}, #{orderId,jdbcType=BIGINT}, #{isUsed,jdbcType=INTEGER}, #{usedTime,jdbcType=TIMESTAMP})</insert><insert id="insertSelective" parameterType="com.itheima.shop.pojo.TradeCoupon" >insert into trade_coupon<trim prefix="(" suffix=")" suffixOverrides="," ><if test="couponId != null" >coupon_id,</if><if test="couponPrice != null" >coupon_price,</if><if test="userId != null" >user_id,</if><if test="orderId != null" >order_id,</if><if test="isUsed != null" >is_used,</if><if test="usedTime != null" >used_time,</if></trim><trim prefix="values (" suffix=")" suffixOverrides="," ><if test="couponId != null" >#{couponId,jdbcType=BIGINT},</if><if test="couponPrice != null" >#{couponPrice,jdbcType=DECIMAL},</if><if test="userId != null" >#{userId,jdbcType=BIGINT},</if><if test="orderId != null" >#{orderId,jdbcType=BIGINT},</if><if test="isUsed != null" >#{isUsed,jdbcType=INTEGER},</if><if test="usedTime != null" >#{usedTime,jdbcType=TIMESTAMP},</if></trim></insert><select id="countByExample" parameterType="com.itheima.shop.pojo.TradeCouponExample" resultType="java.lang.Integer" >select count(*) from trade_coupon<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></select><update id="updateByExampleSelective" parameterType="map" >update trade_coupon<set ><if test="record.couponId != null" >coupon_id = #{record.couponId,jdbcType=BIGINT},</if><if test="record.couponPrice != null" >coupon_price = #{record.couponPrice,jdbcType=DECIMAL},</if><if test="record.userId != null" >user_id = #{record.userId,jdbcType=BIGINT},</if><if test="record.orderId != null" >order_id = #{record.orderId,jdbcType=BIGINT},</if><if test="record.isUsed != null" >is_used = #{record.isUsed,jdbcType=INTEGER},</if><if test="record.usedTime != null" >used_time = #{record.usedTime,jdbcType=TIMESTAMP},</if></set><if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByExample" parameterType="map" >update trade_couponset coupon_id = #{record.couponId,jdbcType=BIGINT},coupon_price = #{record.couponPrice,jdbcType=DECIMAL},user_id = #{record.userId,jdbcType=BIGINT},order_id = #{record.orderId,jdbcType=BIGINT},is_used = #{record.isUsed,jdbcType=INTEGER},used_time = #{record.usedTime,jdbcType=TIMESTAMP}<if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByPrimaryKeySelective" parameterType="com.itheima.shop.pojo.TradeCoupon" >update trade_coupon<set ><if test="couponPrice != null" >coupon_price = #{couponPrice,jdbcType=DECIMAL},</if><if test="userId != null" >user_id = #{userId,jdbcType=BIGINT},</if><if test="orderId != null" >order_id = #{orderId,jdbcType=BIGINT},</if><if test="isUsed != null" >is_used = #{isUsed,jdbcType=INTEGER},</if><if test="usedTime != null" >used_time = #{usedTime,jdbcType=TIMESTAMP},</if></set>where coupon_id = #{couponId,jdbcType=BIGINT}</update><update id="updateByPrimaryKey" parameterType="com.itheima.shop.pojo.TradeCoupon" >update trade_couponset coupon_price = #{couponPrice,jdbcType=DECIMAL},user_id = #{userId,jdbcType=BIGINT},order_id = #{orderId,jdbcType=BIGINT},is_used = #{isUsed,jdbcType=INTEGER},used_time = #{usedTime,jdbcType=TIMESTAMP}where coupon_id = #{couponId,jdbcType=BIGINT}</update>
</mapper>
4.7 创建 application.properties 配置文件。
# application.properties
spring.application.name=dubbo-coupon-provider
spring.dubbo.application.id=dubbo-coupon-provider
spring.dubbo.application.name=dubbo-coupon-provider
spring.dubbo.registry.address=zookeeper://192.168.25.140:2181;zookeeper://192.168.25.140:2182;zookeeper://192.168.25.140:2183
spring.dubbo.server=true
spring.dubbo.protocol.name=dubbo
spring.dubbo.protocol.port=20881# DB
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/trade?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root#spring集成Mybatis环境
#pojo别名扫描包
mybatis.type-aliases-package=com.itheima.shop.pojo
#加载Mybatis映射文件
mybatis.mapper-locations=classpath:com/itheima/shop/mapper/*Mapper.xml# RocketMQ
rocketmq.name-server=192.168.25.135:9876;192.168.25.138:9876
rocketmq.producer.group=orderProducerGroupmq.order.consumer.group.name=order_orderTopic_cancel_group
mq.order.topic=orderTopic

5、创建 shop-goods-service 商品服务 工程。

5.1、在 pom.xml 中,导入依赖坐标。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>shop-parent</artifactId><groupId>com.iteima.shop</groupId><version>1.0-SNAPSHOT</version><relativePath>../shop-parent/pom.xml</relativePath></parent><modelVersion>4.0.0</modelVersion><artifactId>shop-goods-service</artifactId><dependencies><!--mybatis-springboot--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.1</version></dependency><!-- MySQL连接驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-common</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-pojo</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-api</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-pojo</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
<!-- D:\java-test\idea2019\shop\shop-goods-service\pom.xml -->
5.2、 创建 接口 类 TradeGoodsMapper.java
package com.itheima.shop.mapper;import com.itheima.shop.pojo.TradeGoods;
import com.itheima.shop.pojo.TradeGoodsExample;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper
public interface TradeGoodsMapper {int countByExample(TradeGoodsExample example);int deleteByExample(TradeGoodsExample example);int deleteByPrimaryKey(Long goodsId);int insert(TradeGoods record);int insertSelective(TradeGoods record);List<TradeGoods> selectByExample(TradeGoodsExample example);TradeGoods selectByPrimaryKey(Long goodsId);int updateByExampleSelective(@Param("record") TradeGoods record, @Param("example") TradeGoodsExample example);int updateByExample(@Param("record") TradeGoods record, @Param("example") TradeGoodsExample example);int updateByPrimaryKeySelective(TradeGoods record);int updateByPrimaryKey(TradeGoods record);
}
5.3、 创建 接口 类 TradeGoodsNumberLogMapper.java
package com.itheima.shop.mapper;import com.itheima.shop.pojo.TradeGoodsNumberLog;
import com.itheima.shop.pojo.TradeGoodsNumberLogExample;
import com.itheima.shop.pojo.TradeGoodsNumberLogKey;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper
public interface TradeGoodsNumberLogMapper {int countByExample(TradeGoodsNumberLogExample example);int deleteByExample(TradeGoodsNumberLogExample example);int deleteByPrimaryKey(TradeGoodsNumberLogKey key);int insert(TradeGoodsNumberLog record);int insertSelective(TradeGoodsNumberLog record);List<TradeGoodsNumberLog> selectByExample(TradeGoodsNumberLogExample example);TradeGoodsNumberLog selectByPrimaryKey(TradeGoodsNumberLogKey key);int updateByExampleSelective(@Param("record") TradeGoodsNumberLog record, @Param("example") TradeGoodsNumberLogExample example);int updateByExample(@Param("record") TradeGoodsNumberLog record, @Param("example") TradeGoodsNumberLogExample example);int updateByPrimaryKeySelective(TradeGoodsNumberLog record);int updateByPrimaryKey(TradeGoodsNumberLog record);
}
5.4、 创建 接口 类 TradeMqConsumerLogMapper.java
package com.itheima.shop.mapper;import com.itheima.shop.pojo.TradeMqConsumerLog;
import com.itheima.shop.pojo.TradeMqConsumerLogExample;
import com.itheima.shop.pojo.TradeMqConsumerLogKey;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper
public interface TradeMqConsumerLogMapper {int countByExample(TradeMqConsumerLogExample example);int deleteByExample(TradeMqConsumerLogExample example);int deleteByPrimaryKey(TradeMqConsumerLogKey key);int insert(TradeMqConsumerLog record);int insertSelective(TradeMqConsumerLog record);List<TradeMqConsumerLog> selectByExample(TradeMqConsumerLogExample example);TradeMqConsumerLog selectByPrimaryKey(TradeMqConsumerLogKey key);int updateByExampleSelective(@Param("record") TradeMqConsumerLog record, @Param("example") TradeMqConsumerLogExample example);int updateByExample(@Param("record") TradeMqConsumerLog record, @Param("example") TradeMqConsumerLogExample example);int updateByPrimaryKeySelective(TradeMqConsumerLog record);int updateByPrimaryKey(TradeMqConsumerLog record);
}
5.5、 创建 类 CancelMQListener.java
package com.itheima.shop.mq;import com.alibaba.fastjson.JSON;
import com.itheima.constant.ShopCode;
import com.itheima.entity.MQEntity;
import com.itheima.shop.mapper.TradeGoodsMapper;
import com.itheima.shop.mapper.TradeGoodsNumberLogMapper;
import com.itheima.shop.mapper.TradeMqConsumerLogMapper;
import com.itheima.shop.pojo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.util.Date;@Slf4j
@Component
@RocketMQMessageListener(topic = "${mq.order.topic}",consumerGroup = "${mq.order.consumer.group.name}",messageModel = MessageModel.BROADCASTING )
public class CancelMQListener implements RocketMQListener<MessageExt>{@Value("${mq.order.consumer.group.name}")private String groupName;@Autowiredprivate TradeGoodsMapper goodsMapper;@Autowiredprivate TradeMqConsumerLogMapper mqConsumerLogMapper;@Autowiredprivate TradeGoodsNumberLogMapper goodsNumberLogMapper;@Overridepublic void onMessage(MessageExt messageExt) {String msgId=null;String tags=null;String keys=null;String body=null;try {//1. 解析消息内容msgId = messageExt.getMsgId();tags= messageExt.getTags();keys= messageExt.getKeys();body= new String(messageExt.getBody(),"UTF-8");log.info("接受消息成功");//2. 查询消息消费记录TradeMqConsumerLogKey primaryKey = new TradeMqConsumerLogKey();primaryKey.setMsgTag(tags);primaryKey.setMsgKey(keys);primaryKey.setGroupName(groupName);TradeMqConsumerLog mqConsumerLog = mqConsumerLogMapper.selectByPrimaryKey(primaryKey);if(mqConsumerLog!=null){//3. 判断如果消费过...//3.1 获得消息处理状态Integer status = mqConsumerLog.getConsumerStatus();//处理过...返回if(ShopCode.SHOP_MQ_MESSAGE_STATUS_SUCCESS.getCode().intValue()==status.intValue()){log.info("消息:"+msgId+",已经处理过");return;}//正在处理...返回if(ShopCode.SHOP_MQ_MESSAGE_STATUS_PROCESSING.getCode().intValue()==status.intValue()){log.info("消息:"+msgId+",正在处理");return;}//处理失败if(ShopCode.SHOP_MQ_MESSAGE_STATUS_FAIL.getCode().intValue()==status.intValue()){//获得消息处理次数Integer times = mqConsumerLog.getConsumerTimes();if(times>3){log.info("消息:"+msgId+",消息处理超过3次,不能再进行处理了");return;}mqConsumerLog.setConsumerStatus(ShopCode.SHOP_MQ_MESSAGE_STATUS_PROCESSING.getCode());//使用数据库乐观锁更新TradeMqConsumerLogExample example = new TradeMqConsumerLogExample();TradeMqConsumerLogExample.Criteria criteria = example.createCriteria();criteria.andMsgTagEqualTo(mqConsumerLog.getMsgTag());criteria.andMsgKeyEqualTo(mqConsumerLog.getMsgKey());criteria.andGroupNameEqualTo(groupName);criteria.andConsumerTimesEqualTo(mqConsumerLog.getConsumerTimes());int r = mqConsumerLogMapper.updateByExampleSelective(mqConsumerLog, example);if(r<=0){//未修改成功,其他线程并发修改log.info("并发修改,稍后处理");}}}else{//4. 判断如果没有消费过...mqConsumerLog = new TradeMqConsumerLog();mqConsumerLog.setMsgTag(tags);mqConsumerLog.setMsgKey(keys);mqConsumerLog.setGroupName(groupName);mqConsumerLog.setConsumerStatus(ShopCode.SHOP_MQ_MESSAGE_STATUS_PROCESSING.getCode());mqConsumerLog.setMsgBody(body);mqConsumerLog.setMsgId(msgId);mqConsumerLog.setConsumerTimes(0);//将消息处理信息添加到数据库mqConsumerLogMapper.insert(mqConsumerLog);}//5. 回退库存MQEntity mqEntity = JSON.parseObject(body, MQEntity.class);Long goodsId = mqEntity.getGoodsId();TradeGoods goods = goodsMapper.selectByPrimaryKey(goodsId);goods.setGoodsNumber(goods.getGoodsNumber()+mqEntity.getGoodsNum());goodsMapper.updateByPrimaryKey(goods);//6. 将消息的处理状态改为成功mqConsumerLog.setConsumerStatus(ShopCode.SHOP_MQ_MESSAGE_STATUS_SUCCESS.getCode());mqConsumerLog.setConsumerTimestamp(new Date());mqConsumerLogMapper.updateByPrimaryKey(mqConsumerLog);log.info("回退库存成功");} catch (Exception e) {e.printStackTrace();TradeMqConsumerLogKey primaryKey = new TradeMqConsumerLogKey();primaryKey.setMsgTag(tags);primaryKey.setMsgKey(keys);primaryKey.setGroupName(groupName);TradeMqConsumerLog mqConsumerLog = mqConsumerLogMapper.selectByPrimaryKey(primaryKey);if(mqConsumerLog==null){//数据库未有记录mqConsumerLog = new TradeMqConsumerLog();mqConsumerLog.setMsgTag(tags);mqConsumerLog.setMsgKey(keys);mqConsumerLog.setGroupName(groupName);mqConsumerLog.setConsumerStatus(ShopCode.SHOP_MQ_MESSAGE_STATUS_FAIL.getCode());mqConsumerLog.setMsgBody(body);mqConsumerLog.setMsgId(msgId);mqConsumerLog.setConsumerTimes(1);mqConsumerLogMapper.insert(mqConsumerLog);}else{mqConsumerLog.setConsumerTimes(mqConsumerLog.getConsumerTimes()+1);mqConsumerLogMapper.updateByPrimaryKeySelective(mqConsumerLog);}}}
}
5.6、 创建 类 GoodsServiceImpl.java
package com.itheima.shop.service.impl;import com.alibaba.dubbo.config.annotation.Service;
import com.itheima.api.IGoodsService;
import com.itheima.constant.ShopCode;
import com.itheima.entity.Result;
import com.itheima.exception.CastException;
import com.itheima.shop.mapper.TradeGoodsMapper;
import com.itheima.shop.mapper.TradeGoodsNumberLogMapper;
import com.itheima.shop.pojo.TradeGoods;
import com.itheima.shop.pojo.TradeGoodsNumberLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.Date;@Component
@Service(interfaceClass = IGoodsService.class)
public class GoodsServiceImpl implements IGoodsService {@Autowiredprivate TradeGoodsMapper goodsMapper;@Autowiredprivate TradeGoodsNumberLogMapper goodsNumberLogMapper;@Overridepublic TradeGoods findOne(Long goodsId) {if (goodsId == null) {CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);}return goodsMapper.selectByPrimaryKey(goodsId);}@Overridepublic Result reduceGoodsNum(TradeGoodsNumberLog goodsNumberLog) {if (goodsNumberLog == null ||goodsNumberLog.getGoodsNumber() == null ||goodsNumberLog.getOrderId() == null ||goodsNumberLog.getGoodsNumber() == null ||goodsNumberLog.getGoodsNumber().intValue() <= 0) {CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);}TradeGoods goods = goodsMapper.selectByPrimaryKey(goodsNumberLog.getGoodsId());if(goods.getGoodsNumber()<goodsNumberLog.getGoodsNumber()){//库存不足CastException.cast(ShopCode.SHOP_GOODS_NUM_NOT_ENOUGH);}//减库存goods.setGoodsNumber(goods.getGoodsNumber()-goodsNumberLog.getGoodsNumber());goodsMapper.updateByPrimaryKey(goods);//记录库存操作日志goodsNumberLog.setGoodsNumber(-(goodsNumberLog.getGoodsNumber()));goodsNumberLog.setLogTime(new Date());goodsNumberLogMapper.insert(goodsNumberLog);return new Result(ShopCode.SHOP_SUCCESS.getSuccess(),ShopCode.SHOP_SUCCESS.getMessage());}}
5.7、 创建 类 GoodsServiceApplication.java
package com.itheima.shop;import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@EnableDubboConfiguration
public class GoodsServiceApplication {public static void main(String[] args) {SpringApplication.run(GoodsServiceApplication.class,args);}}
5.8、 创建 文件 TradeGoodsMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.itheima.shop.mapper.TradeGoodsMapper" ><resultMap id="BaseResultMap" type="com.itheima.shop.pojo.TradeGoods" ><id column="goods_id" property="goodsId" jdbcType="BIGINT" /><result column="goods_name" property="goodsName" jdbcType="VARCHAR" /><result column="goods_number" property="goodsNumber" jdbcType="INTEGER" /><result column="goods_price" property="goodsPrice" jdbcType="DECIMAL" /><result column="goods_desc" property="goodsDesc" jdbcType="VARCHAR" /><result column="add_time" property="addTime" jdbcType="TIMESTAMP" /></resultMap><sql id="Example_Where_Clause" ><where ><foreach collection="oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Update_By_Example_Where_Clause" ><where ><foreach collection="example.oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Base_Column_List" >goods_id, goods_name, goods_number, goods_price, goods_desc, add_time</sql><select id="selectByExample" resultMap="BaseResultMap" parameterType="com.itheima.shop.pojo.TradeGoodsExample" >select<if test="distinct" >distinct</if><include refid="Base_Column_List" />from trade_goods<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if><if test="orderByClause != null" >order by ${orderByClause}</if></select><select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >select <include refid="Base_Column_List" />from trade_goodswhere goods_id = #{goodsId,jdbcType=BIGINT}</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Long" >delete from trade_goodswhere goods_id = #{goodsId,jdbcType=BIGINT}</delete><delete id="deleteByExample" parameterType="com.itheima.shop.pojo.TradeGoodsExample" >delete from trade_goods<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></delete><insert id="insert" parameterType="com.itheima.shop.pojo.TradeGoods" >insert into trade_goods (goods_id, goods_name, goods_number, goods_price, goods_desc, add_time)values (#{goodsId,jdbcType=BIGINT}, #{goodsName,jdbcType=VARCHAR}, #{goodsNumber,jdbcType=INTEGER}, #{goodsPrice,jdbcType=DECIMAL}, #{goodsDesc,jdbcType=VARCHAR}, #{addTime,jdbcType=TIMESTAMP})</insert><insert id="insertSelective" parameterType="com.itheima.shop.pojo.TradeGoods" >insert into trade_goods<trim prefix="(" suffix=")" suffixOverrides="," ><if test="goodsId != null" >goods_id,</if><if test="goodsName != null" >goods_name,</if><if test="goodsNumber != null" >goods_number,</if><if test="goodsPrice != null" >goods_price,</if><if test="goodsDesc != null" >goods_desc,</if><if test="addTime != null" >add_time,</if></trim><trim prefix="values (" suffix=")" suffixOverrides="," ><if test="goodsId != null" >#{goodsId,jdbcType=BIGINT},</if><if test="goodsName != null" >#{goodsName,jdbcType=VARCHAR},</if><if test="goodsNumber != null" >#{goodsNumber,jdbcType=INTEGER},</if><if test="goodsPrice != null" >#{goodsPrice,jdbcType=DECIMAL},</if><if test="goodsDesc != null" >#{goodsDesc,jdbcType=VARCHAR},</if><if test="addTime != null" >#{addTime,jdbcType=TIMESTAMP},</if></trim></insert><select id="countByExample" parameterType="com.itheima.shop.pojo.TradeGoodsExample" resultType="java.lang.Integer" >select count(*) from trade_goods<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></select><update id="updateByExampleSelective" parameterType="map" >update trade_goods<set ><if test="record.goodsId != null" >goods_id = #{record.goodsId,jdbcType=BIGINT},</if><if test="record.goodsName != null" >goods_name = #{record.goodsName,jdbcType=VARCHAR},</if><if test="record.goodsNumber != null" >goods_number = #{record.goodsNumber,jdbcType=INTEGER},</if><if test="record.goodsPrice != null" >goods_price = #{record.goodsPrice,jdbcType=DECIMAL},</if><if test="record.goodsDesc != null" >goods_desc = #{record.goodsDesc,jdbcType=VARCHAR},</if><if test="record.addTime != null" >add_time = #{record.addTime,jdbcType=TIMESTAMP},</if></set><if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByExample" parameterType="map" >update trade_goodsset goods_id = #{record.goodsId,jdbcType=BIGINT},goods_name = #{record.goodsName,jdbcType=VARCHAR},goods_number = #{record.goodsNumber,jdbcType=INTEGER},goods_price = #{record.goodsPrice,jdbcType=DECIMAL},goods_desc = #{record.goodsDesc,jdbcType=VARCHAR},add_time = #{record.addTime,jdbcType=TIMESTAMP}<if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByPrimaryKeySelective" parameterType="com.itheima.shop.pojo.TradeGoods" >update trade_goods<set ><if test="goodsName != null" >goods_name = #{goodsName,jdbcType=VARCHAR},</if><if test="goodsNumber != null" >goods_number = #{goodsNumber,jdbcType=INTEGER},</if><if test="goodsPrice != null" >goods_price = #{goodsPrice,jdbcType=DECIMAL},</if><if test="goodsDesc != null" >goods_desc = #{goodsDesc,jdbcType=VARCHAR},</if><if test="addTime != null" >add_time = #{addTime,jdbcType=TIMESTAMP},</if></set>where goods_id = #{goodsId,jdbcType=BIGINT}</update><update id="updateByPrimaryKey" parameterType="com.itheima.shop.pojo.TradeGoods" >update trade_goodsset goods_name = #{goodsName,jdbcType=VARCHAR},goods_number = #{goodsNumber,jdbcType=INTEGER},goods_price = #{goodsPrice,jdbcType=DECIMAL},goods_desc = #{goodsDesc,jdbcType=VARCHAR},add_time = #{addTime,jdbcType=TIMESTAMP}where goods_id = #{goodsId,jdbcType=BIGINT}</update>
</mapper>
5.9、 创建 文件 TradeGoodsNumberLogMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.itheima.shop.mapper.TradeGoodsNumberLogMapper" ><resultMap id="BaseResultMap" type="com.itheima.shop.pojo.TradeGoodsNumberLog" ><id column="goods_id" property="goodsId" jdbcType="BIGINT" /><id column="order_id" property="orderId" jdbcType="BIGINT" /><result column="goods_number" property="goodsNumber" jdbcType="INTEGER" /><result column="log_time" property="logTime" jdbcType="TIMESTAMP" /></resultMap><sql id="Example_Where_Clause" ><where ><foreach collection="oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Update_By_Example_Where_Clause" ><where ><foreach collection="example.oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Base_Column_List" >goods_id, order_id, goods_number, log_time</sql><select id="selectByExample" resultMap="BaseResultMap" parameterType="com.itheima.shop.pojo.TradeGoodsNumberLogExample" >select<if test="distinct" >distinct</if><include refid="Base_Column_List" />from trade_goods_number_log<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if><if test="orderByClause != null" >order by ${orderByClause}</if></select><select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="com.itheima.shop.pojo.TradeGoodsNumberLogKey" >select <include refid="Base_Column_List" />from trade_goods_number_logwhere goods_id = #{goodsId,jdbcType=BIGINT}and order_id = #{orderId,jdbcType=BIGINT}</select><delete id="deleteByPrimaryKey" parameterType="com.itheima.shop.pojo.TradeGoodsNumberLogKey" >delete from trade_goods_number_logwhere goods_id = #{goodsId,jdbcType=BIGINT}and order_id = #{orderId,jdbcType=BIGINT}</delete><delete id="deleteByExample" parameterType="com.itheima.shop.pojo.TradeGoodsNumberLogExample" >delete from trade_goods_number_log<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></delete><insert id="insert" parameterType="com.itheima.shop.pojo.TradeGoodsNumberLog" >insert into trade_goods_number_log (goods_id, order_id, goods_number, log_time)values (#{goodsId,jdbcType=BIGINT}, #{orderId,jdbcType=BIGINT}, #{goodsNumber,jdbcType=INTEGER}, #{logTime,jdbcType=TIMESTAMP})</insert><insert id="insertSelective" parameterType="com.itheima.shop.pojo.TradeGoodsNumberLog" >insert into trade_goods_number_log<trim prefix="(" suffix=")" suffixOverrides="," ><if test="goodsId != null" >goods_id,</if><if test="orderId != null" >order_id,</if><if test="goodsNumber != null" >goods_number,</if><if test="logTime != null" >log_time,</if></trim><trim prefix="values (" suffix=")" suffixOverrides="," ><if test="goodsId != null" >#{goodsId,jdbcType=BIGINT},</if><if test="orderId != null" >#{orderId,jdbcType=BIGINT},</if><if test="goodsNumber != null" >#{goodsNumber,jdbcType=INTEGER},</if><if test="logTime != null" >#{logTime,jdbcType=TIMESTAMP},</if></trim></insert><select id="countByExample" parameterType="com.itheima.shop.pojo.TradeGoodsNumberLogExample" resultType="java.lang.Integer" >select count(*) from trade_goods_number_log<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></select><update id="updateByExampleSelective" parameterType="map" >update trade_goods_number_log<set ><if test="record.goodsId != null" >goods_id = #{record.goodsId,jdbcType=BIGINT},</if><if test="record.orderId != null" >order_id = #{record.orderId,jdbcType=BIGINT},</if><if test="record.goodsNumber != null" >goods_number = #{record.goodsNumber,jdbcType=INTEGER},</if><if test="record.logTime != null" >log_time = #{record.logTime,jdbcType=TIMESTAMP},</if></set><if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByExample" parameterType="map" >update trade_goods_number_logset goods_id = #{record.goodsId,jdbcType=BIGINT},order_id = #{record.orderId,jdbcType=BIGINT},goods_number = #{record.goodsNumber,jdbcType=INTEGER},log_time = #{record.logTime,jdbcType=TIMESTAMP}<if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByPrimaryKeySelective" parameterType="com.itheima.shop.pojo.TradeGoodsNumberLog" >update trade_goods_number_log<set ><if test="goodsNumber != null" >goods_number = #{goodsNumber,jdbcType=INTEGER},</if><if test="logTime != null" >log_time = #{logTime,jdbcType=TIMESTAMP},</if></set>where goods_id = #{goodsId,jdbcType=BIGINT}and order_id = #{orderId,jdbcType=BIGINT}</update><update id="updateByPrimaryKey" parameterType="com.itheima.shop.pojo.TradeGoodsNumberLog" >update trade_goods_number_logset goods_number = #{goodsNumber,jdbcType=INTEGER},log_time = #{logTime,jdbcType=TIMESTAMP}where goods_id = #{goodsId,jdbcType=BIGINT}and order_id = #{orderId,jdbcType=BIGINT}</update>
</mapper>
5.10、 创建 文件 TradeMqConsumerLogMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.itheima.shop.mapper.TradeMqConsumerLogMapper" ><resultMap id="BaseResultMap" type="com.itheima.shop.pojo.TradeMqConsumerLog" ><id column="group_name" property="groupName" jdbcType="VARCHAR" /><id column="msg_tag" property="msgTag" jdbcType="VARCHAR" /><id column="msg_key" property="msgKey" jdbcType="VARCHAR" /><result column="msg_id" property="msgId" jdbcType="VARCHAR" /><result column="msg_body" property="msgBody" jdbcType="VARCHAR" /><result column="consumer_status" property="consumerStatus" jdbcType="INTEGER" /><result column="consumer_times" property="consumerTimes" jdbcType="INTEGER" /><result column="consumer_timestamp" property="consumerTimestamp" jdbcType="TIMESTAMP" /><result column="remark" property="remark" jdbcType="VARCHAR" /></resultMap><sql id="Example_Where_Clause" ><where ><foreach collection="oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Update_By_Example_Where_Clause" ><where ><foreach collection="example.oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Base_Column_List" >group_name, msg_tag, msg_key, msg_id, msg_body, consumer_status, consumer_times, consumer_timestamp, remark</sql><select id="selectByExample" resultMap="BaseResultMap" parameterType="com.itheima.shop.pojo.TradeMqConsumerLogExample" >select<if test="distinct" >distinct</if><include refid="Base_Column_List" />from trade_mq_consumer_log<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if><if test="orderByClause != null" >order by ${orderByClause}</if></select><select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="com.itheima.shop.pojo.TradeMqConsumerLogKey" >select <include refid="Base_Column_List" />from trade_mq_consumer_logwhere group_name = #{groupName,jdbcType=VARCHAR}and msg_tag = #{msgTag,jdbcType=VARCHAR}and msg_key = #{msgKey,jdbcType=VARCHAR}</select><delete id="deleteByPrimaryKey" parameterType="com.itheima.shop.pojo.TradeMqConsumerLogKey" >delete from trade_mq_consumer_logwhere group_name = #{groupName,jdbcType=VARCHAR}and msg_tag = #{msgTag,jdbcType=VARCHAR}and msg_key = #{msgKey,jdbcType=VARCHAR}</delete><delete id="deleteByExample" parameterType="com.itheima.shop.pojo.TradeMqConsumerLogExample" >delete from trade_mq_consumer_log<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></delete><insert id="insert" parameterType="com.itheima.shop.pojo.TradeMqConsumerLog" >insert into trade_mq_consumer_log (group_name, msg_tag, msg_key, msg_id, msg_body, consumer_status, consumer_times, consumer_timestamp, remark)values (#{groupName,jdbcType=VARCHAR}, #{msgTag,jdbcType=VARCHAR}, #{msgKey,jdbcType=VARCHAR}, #{msgId,jdbcType=VARCHAR}, #{msgBody,jdbcType=VARCHAR}, #{consumerStatus,jdbcType=INTEGER}, #{consumerTimes,jdbcType=INTEGER}, #{consumerTimestamp,jdbcType=TIMESTAMP}, #{remark,jdbcType=VARCHAR})</insert><insert id="insertSelective" parameterType="com.itheima.shop.pojo.TradeMqConsumerLog" >insert into trade_mq_consumer_log<trim prefix="(" suffix=")" suffixOverrides="," ><if test="groupName != null" >group_name,</if><if test="msgTag != null" >msg_tag,</if><if test="msgKey != null" >msg_key,</if><if test="msgId != null" >msg_id,</if><if test="msgBody != null" >msg_body,</if><if test="consumerStatus != null" >consumer_status,</if><if test="consumerTimes != null" >consumer_times,</if><if test="consumerTimestamp != null" >consumer_timestamp,</if><if test="remark != null" >remark,</if></trim><trim prefix="values (" suffix=")" suffixOverrides="," ><if test="groupName != null" >#{groupName,jdbcType=VARCHAR},</if><if test="msgTag != null" >#{msgTag,jdbcType=VARCHAR},</if><if test="msgKey != null" >#{msgKey,jdbcType=VARCHAR},</if><if test="msgId != null" >#{msgId,jdbcType=VARCHAR},</if><if test="msgBody != null" >#{msgBody,jdbcType=VARCHAR},</if><if test="consumerStatus != null" >#{consumerStatus,jdbcType=INTEGER},</if><if test="consumerTimes != null" >#{consumerTimes,jdbcType=INTEGER},</if><if test="consumerTimestamp != null" >#{consumerTimestamp,jdbcType=TIMESTAMP},</if><if test="remark != null" >#{remark,jdbcType=VARCHAR},</if></trim></insert><select id="countByExample" parameterType="com.itheima.shop.pojo.TradeMqConsumerLogExample" resultType="java.lang.Integer" >select count(*) from trade_mq_consumer_log<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></select><update id="updateByExampleSelective" parameterType="map" >update trade_mq_consumer_log<set ><if test="record.groupName != null" >group_name = #{record.groupName,jdbcType=VARCHAR},</if><if test="record.msgTag != null" >msg_tag = #{record.msgTag,jdbcType=VARCHAR},</if><if test="record.msgKey != null" >msg_key = #{record.msgKey,jdbcType=VARCHAR},</if><if test="record.msgId != null" >msg_id = #{record.msgId,jdbcType=VARCHAR},</if><if test="record.msgBody != null" >msg_body = #{record.msgBody,jdbcType=VARCHAR},</if><if test="record.consumerStatus != null" >consumer_status = #{record.consumerStatus,jdbcType=INTEGER},</if><if test="record.consumerTimes != null" >consumer_times = #{record.consumerTimes,jdbcType=INTEGER},</if><if test="record.consumerTimestamp != null" >consumer_timestamp = #{record.consumerTimestamp,jdbcType=TIMESTAMP},</if><if test="record.remark != null" >remark = #{record.remark,jdbcType=VARCHAR},</if></set><if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByExample" parameterType="map" >update trade_mq_consumer_logset group_name = #{record.groupName,jdbcType=VARCHAR},msg_tag = #{record.msgTag,jdbcType=VARCHAR},msg_key = #{record.msgKey,jdbcType=VARCHAR},msg_id = #{record.msgId,jdbcType=VARCHAR},msg_body = #{record.msgBody,jdbcType=VARCHAR},consumer_status = #{record.consumerStatus,jdbcType=INTEGER},consumer_times = #{record.consumerTimes,jdbcType=INTEGER},consumer_timestamp = #{record.consumerTimestamp,jdbcType=TIMESTAMP},remark = #{record.remark,jdbcType=VARCHAR}<if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByPrimaryKeySelective" parameterType="com.itheima.shop.pojo.TradeMqConsumerLog" >update trade_mq_consumer_log<set ><if test="msgId != null" >msg_id = #{msgId,jdbcType=VARCHAR},</if><if test="msgBody != null" >msg_body = #{msgBody,jdbcType=VARCHAR},</if><if test="consumerStatus != null" >consumer_status = #{consumerStatus,jdbcType=INTEGER},</if><if test="consumerTimes != null" >consumer_times = #{consumerTimes,jdbcType=INTEGER},</if><if test="consumerTimestamp != null" >consumer_timestamp = #{consumerTimestamp,jdbcType=TIMESTAMP},</if><if test="remark != null" >remark = #{remark,jdbcType=VARCHAR},</if></set>where group_name = #{groupName,jdbcType=VARCHAR}and msg_tag = #{msgTag,jdbcType=VARCHAR}and msg_key = #{msgKey,jdbcType=VARCHAR}</update><update id="updateByPrimaryKey" parameterType="com.itheima.shop.pojo.TradeMqConsumerLog" >update trade_mq_consumer_logset msg_id = #{msgId,jdbcType=VARCHAR},msg_body = #{msgBody,jdbcType=VARCHAR},consumer_status = #{consumerStatus,jdbcType=INTEGER},consumer_times = #{consumerTimes,jdbcType=INTEGER},consumer_timestamp = #{consumerTimestamp,jdbcType=TIMESTAMP},remark = #{remark,jdbcType=VARCHAR}where group_name = #{groupName,jdbcType=VARCHAR}and msg_tag = #{msgTag,jdbcType=VARCHAR}and msg_key = #{msgKey,jdbcType=VARCHAR}</update>
</mapper>
5.11、 创建 文件 application.properties
spring.application.name=dubbo-goods-provider
spring.dubbo.application.id=dubbo-goods-provider
spring.dubbo.application.name=dubbo-goods-provider
spring.dubbo.registry.address=zookeeper://192.168.25.140:2181;zookeeper://192.168.25.140:2182;zookeeper://192.168.25.140:2183
spring.dubbo.server=true
spring.dubbo.protocol.name=dubbo
spring.dubbo.protocol.port=20882# DB
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/trade?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root#spring集成Mybatis环境
#pojo别名扫描包
mybatis.type-aliases-package=com.itheima.shop.pojo
#加载Mybatis映射文件
mybatis.mapper-locations=classpath:com/itheima/shop/mapper/*Mapper.xml# RocketMQ
rocketmq.name-server=192.168.25.135:9876;192.168.25.138:9876
rocketmq.producer.group=orderProducerGroupmq.order.consumer.group.name=order_orderTopic_cancel_group
mq.order.topic=orderTopic

6、创建 shop-order-service 订单服务 工程。

6.1、在 pom.xml 中,导入依赖坐标。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>shop-parent</artifactId><groupId>com.iteima.shop</groupId><version>1.0-SNAPSHOT</version><relativePath>../shop-parent/pom.xml</relativePath></parent><modelVersion>4.0.0</modelVersion><artifactId>shop-order-service</artifactId><dependencies><!--mybatis-springboot--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.1</version></dependency><!-- MySQL连接驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--common--><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-common</artifactId><version>1.0-SNAPSHOT</version></dependency><!--接口--><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-api</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-pojo</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
<!-- D:\java-test\idea2019\shop\shop-order-service\pom.xml -->
6.2、创建 接口 类 TradeOrderMapper.java
package com.itheima.shop.mapper;import com.itheima.shop.pojo.TradeOrder;
import com.itheima.shop.pojo.TradeOrderExample;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper
public interface TradeOrderMapper {int countByExample(TradeOrderExample example);int deleteByExample(TradeOrderExample example);int deleteByPrimaryKey(Long orderId);int insert(TradeOrder record);int insertSelective(TradeOrder record);List<TradeOrder> selectByExample(TradeOrderExample example);TradeOrder selectByPrimaryKey(Long orderId);int updateByExampleSelective(@Param("record") TradeOrder record, @Param("example") TradeOrderExample example);int updateByExample(@Param("record") TradeOrder record, @Param("example") TradeOrderExample example);int updateByPrimaryKeySelective(TradeOrder record);int updateByPrimaryKey(TradeOrder record);
}
6.3、创建 类 CancelMQListener.java
package com.itheima.shop.mq;import com.alibaba.fastjson.JSON;
import com.itheima.constant.ShopCode;
import com.itheima.entity.MQEntity;
import com.itheima.shop.mapper.TradeOrderMapper;
import com.itheima.shop.pojo.TradeOrder;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.io.UnsupportedEncodingException;@Slf4j
@Component
@RocketMQMessageListener(topic = "${mq.order.topic}",consumerGroup = "${mq.order.consumer.group.name}",messageModel = MessageModel.BROADCASTING )
public class CancelMQListener implements RocketMQListener<MessageExt>{@Autowiredprivate TradeOrderMapper orderMapper;@Overridepublic void onMessage(MessageExt messageExt) {try {//1. 解析消息内容String body = new String(messageExt.getBody(),"UTF-8");MQEntity mqEntity = JSON.parseObject(body, MQEntity.class);log.info("接受消息成功");//2. 查询订单TradeOrder order = orderMapper.selectByPrimaryKey(mqEntity.getOrderId());//3.更新订单状态为取消order.setOrderStatus(ShopCode.SHOP_ORDER_CANCEL.getCode());orderMapper.updateByPrimaryKey(order);log.info("订单状态设置为取消");} catch (UnsupportedEncodingException e) {e.printStackTrace();log.info("订单取消失败");}}
}
6.4、创建 类 PaymentListener.java
package com.itheima.shop.mq;import com.alibaba.fastjson.JSON;
import com.itheima.constant.ShopCode;
import com.itheima.shop.mapper.TradeOrderMapper;
import com.itheima.shop.pojo.TradeOrder;
import com.itheima.shop.pojo.TradePay;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.io.UnsupportedEncodingException;@Slf4j
@Component
@RocketMQMessageListener(topic = "${mq.pay.topic}",consumerGroup = "${mq.pay.consumer.group.name}",messageModel = MessageModel.BROADCASTING)
public class PaymentListener implements RocketMQListener<MessageExt>{@Autowiredprivate TradeOrderMapper orderMapper;@Overridepublic void onMessage(MessageExt messageExt) {log.info("接收到支付成功消息");try {//1.解析消息内容String body = new String(messageExt.getBody(),"UTF-8");TradePay tradePay = JSON.parseObject(body,TradePay.class);//2.根据订单ID查询订单对象TradeOrder tradeOrder = orderMapper.selectByPrimaryKey(tradePay.getOrderId());//3.更改订单支付状态为已支付tradeOrder.setPayStatus(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode());//4.更新订单数据到数据库orderMapper.updateByPrimaryKey(tradeOrder);log.info("更改订单支付状态为已支付");} catch (UnsupportedEncodingException e) {e.printStackTrace();}}
}
6.5、创建 类 OrderServiceImpl.java
package com.itheima.shop.service;import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.itheima.api.ICouponService;
import com.itheima.api.IGoodsService;
import com.itheima.api.IOrderService;
import com.itheima.api.IUserService;
import com.itheima.constant.ShopCode;
import com.itheima.entity.MQEntity;
import com.itheima.entity.Result;
import com.itheima.exception.CastException;
import com.itheima.shop.mapper.TradeOrderMapper;
import com.itheima.shop.pojo.*;
import com.itheima.utils.IDWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.math.BigDecimal;
import java.util.Date;@Slf4j
@Component
@Service(interfaceClass = IOrderService.class)
public class OrderServiceImpl implements IOrderService {@Referenceprivate IGoodsService goodsService;@Referenceprivate IUserService userService;@Referenceprivate ICouponService couponService;@Value("${mq.order.topic}")private String topic;@Value("${mq.order.tag.cancel}")private String tag;@Autowiredprivate TradeOrderMapper orderMapper;@Autowiredprivate IDWorker idWorker;@Autowiredprivate RocketMQTemplate rocketMQTemplate;@Overridepublic Result confirmOrder(TradeOrder order) {//1.校验订单checkOrder(order);//2.生成预订单Long orderId = savePreOrder(order);try {//3.扣减库存reduceGoodsNum(order);//4.扣减优惠券updateCouponStatus(order);//5.使用余额reduceMoneyPaid(order);//模拟异常抛出//CastException.cast(ShopCode.SHOP_FAIL);//6.确认订单updateOrderStatus(order);//7.返回成功状态return new Result(ShopCode.SHOP_SUCCESS.getSuccess(),ShopCode.SHOP_SUCCESS.getMessage());} catch (Exception e) {//1.确认订单失败,发送消息MQEntity mqEntity = new MQEntity();mqEntity.setOrderId(orderId);mqEntity.setUserId(order.getUserId());mqEntity.setUserMoney(order.getMoneyPaid());mqEntity.setGoodsId(order.getGoodsId());mqEntity.setGoodsNum(order.getGoodsNumber());mqEntity.setCouponId(order.getCouponId());//2.返回订单确认失败消息try {sendCancelOrder(topic,tag,order.getOrderId().toString(), JSON.toJSONString(mqEntity));} catch (Exception e1) {e1.printStackTrace();}return new Result(ShopCode.SHOP_FAIL.getSuccess(),ShopCode.SHOP_FAIL.getMessage());}}/*** 发送订单确认失败消息* @param topic* @param tag* @param keys* @param body*/private void sendCancelOrder(String topic, String tag, String keys, String body) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {Message message = new Message(topic,tag,keys,body.getBytes());rocketMQTemplate.getProducer().send(message);}/*** 确认订单* @param order*/private void updateOrderStatus(TradeOrder order) {order.setOrderStatus(ShopCode.SHOP_ORDER_CONFIRM.getCode());order.setPayStatus(ShopCode.SHOP_ORDER_PAY_STATUS_NO_PAY.getCode());order.setConfirmTime(new Date());int r = orderMapper.updateByPrimaryKey(order);if(r<=0){CastException.cast(ShopCode.SHOP_ORDER_CONFIRM_FAIL);}log.info("订单:"+order.getOrderId()+"确认订单成功");}/*** 扣减余额* @param order*/private void reduceMoneyPaid(TradeOrder order) {if(order.getMoneyPaid()!=null && order.getMoneyPaid().compareTo(BigDecimal.ZERO)==1){TradeUserMoneyLog userMoneyLog = new TradeUserMoneyLog();userMoneyLog.setOrderId(order.getOrderId());userMoneyLog.setUserId(order.getUserId());userMoneyLog.setUseMoney(order.getMoneyPaid());userMoneyLog.setMoneyLogType(ShopCode.SHOP_USER_MONEY_PAID.getCode());Result result = userService.updateMoneyPaid(userMoneyLog);if(result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess())){CastException.cast(ShopCode.SHOP_USER_MONEY_REDUCE_FAIL);}log.info("订单:"+order.getOrderId()+",扣减余额成功");}}/*** 使用优惠券* @param order*/private void updateCouponStatus(TradeOrder order) {if(order.getCouponId()!=null){TradeCoupon coupon = couponService.findOne(order.getCouponId());coupon.setOrderId(order.getOrderId());coupon.setIsUsed(ShopCode.SHOP_COUPON_ISUSED.getCode());coupon.setUsedTime(new Date());//更新优惠券状态Result result =  couponService.updateCouponStatus(coupon);if(result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess())){CastException.cast(ShopCode.SHOP_COUPON_USE_FAIL);}log.info("订单:"+order.getOrderId()+",使用优惠券");}}/*** 扣减库存* @param order*/private void reduceGoodsNum(TradeOrder order) {TradeGoodsNumberLog goodsNumberLog = new TradeGoodsNumberLog();goodsNumberLog.setOrderId(order.getOrderId());goodsNumberLog.setGoodsId(order.getGoodsId());goodsNumberLog.setGoodsNumber(order.getGoodsNumber());Result result = goodsService.reduceGoodsNum(goodsNumberLog);if(result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess())){CastException.cast(ShopCode.SHOP_REDUCE_GOODS_NUM_FAIL);}log.info("订单:"+order.getOrderId()+"扣减库存成功");}/*** 生成预订单** @param order* @return*/private Long savePreOrder(TradeOrder order) {//1. 设置订单状态为不可见order.setOrderStatus(ShopCode.SHOP_ORDER_NO_CONFIRM.getCode());//2. 设置订单IDlong orderId = idWorker.nextId();order.setOrderId(orderId);//3. 核算订单运费BigDecimal shippingFee = calculateShippingFee(order.getOrderAmount());if(order.getShippingFee().compareTo(shippingFee)!=0){CastException.cast(ShopCode.SHOP_ORDER_SHIPPINGFEE_INVALID);}//4. 核算订单总金额是否合法BigDecimal orderAmount = order.getGoodsPrice().multiply(new BigDecimal(order.getGoodsNumber()));orderAmount.add(shippingFee);if(order.getOrderAmount().compareTo(orderAmount)!=0){CastException.cast(ShopCode.SHOP_ORDERAMOUNT_INVALID);}//5.判断用户是否使用余额BigDecimal moneyPaid = order.getMoneyPaid();if(moneyPaid!=null){//5.1 订单中余额是否合法int r = moneyPaid.compareTo(BigDecimal.ZERO);//余额小于0if(r==-1){CastException.cast(ShopCode.SHOP_MONEY_PAID_LESS_ZERO);}//余额大于0if(r==1){TradeUser user = userService.findOne(order.getUserId());if(moneyPaid.compareTo(new BigDecimal(user.getUserMoney()))==1){CastException.cast(ShopCode.SHOP_MONEY_PAID_INVALID);}}}else{order.setMoneyPaid(BigDecimal.ZERO);}//6.判断用户是否使用优惠券Long couponId = order.getCouponId();if(couponId!=null){TradeCoupon coupon = couponService.findOne(couponId);//6.1 判断优惠券是否存在if(coupon==null){CastException.cast(ShopCode.SHOP_COUPON_NO_EXIST);}//6.2 判断优惠券是否已经被使用if(coupon.getIsUsed().intValue()==ShopCode.SHOP_COUPON_ISUSED.getCode().intValue()){CastException.cast(ShopCode.SHOP_COUPON_ISUSED);}order.setCouponPaid(coupon.getCouponPrice());}else{order.setCouponPaid(BigDecimal.ZERO);}//7.核算订单支付金额    订单总金额-余额-优惠券金额BigDecimal payAmount = order.getOrderAmount().subtract(order.getMoneyPaid()).subtract(order.getCouponPaid());order.setPayAmount(payAmount);//8.设置下单时间order.setAddTime(new Date());//9.保存订单到数据库orderMapper.insert(order);//10.返回订单IDreturn orderId;}/*** 核算运费* @param orderAmount* @return*/private BigDecimal calculateShippingFee(BigDecimal orderAmount) {if(orderAmount.compareTo(new BigDecimal(100))==1){return BigDecimal.ZERO;}else{return new BigDecimal(10);}}/*** 校验订单** @param order*/private void checkOrder(TradeOrder order) {//1.校验订单是否存在if (order == null) {CastException.cast(ShopCode.SHOP_ORDER_INVALID);}//2.校验订单中的商品是否存在TradeGoods goods = goodsService.findOne(order.getGoodsId());if (goods == null) {CastException.cast(ShopCode.SHOP_GOODS_NO_EXIST);}//3.校验下单用户是否存在TradeUser user = userService.findOne(order.getUserId());if (user == null) {CastException.cast(ShopCode.SHOP_USER_NO_EXIST);}//4.校验商品单价是否合法if (order.getGoodsPrice().compareTo(goods.getGoodsPrice()) != 0) {CastException.cast(ShopCode.SHOP_GOODS_PRICE_INVALID);}//5.校验订单商品数量是否合法if (order.getGoodsNumber() >= goods.getGoodsNumber()) {CastException.cast(ShopCode.SHOP_GOODS_NUM_NOT_ENOUGH);}log.info("校验订单通过");}}
6.6、创建 类 OrderServiceApplication.java
package com.itheima.shop;import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import com.itheima.utils.IDWorker;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;@SpringBootApplication
@EnableDubboConfiguration
public class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class,args);}@Beanpublic IDWorker getBean(){return new IDWorker(1,1);}}
6.7、创建 文件 TradeOrderMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.itheima.shop.mapper.TradeOrderMapper" ><resultMap id="BaseResultMap" type="com.itheima.shop.pojo.TradeOrder" ><id column="order_id" property="orderId" jdbcType="BIGINT" /><result column="user_id" property="userId" jdbcType="BIGINT" /><result column="order_status" property="orderStatus" jdbcType="INTEGER" /><result column="pay_status" property="payStatus" jdbcType="INTEGER" /><result column="shipping_status" property="shippingStatus" jdbcType="INTEGER" /><result column="address" property="address" jdbcType="VARCHAR" /><result column="consignee" property="consignee" jdbcType="VARCHAR" /><result column="goods_id" property="goodsId" jdbcType="BIGINT" /><result column="goods_number" property="goodsNumber" jdbcType="INTEGER" /><result column="goods_price" property="goodsPrice" jdbcType="DECIMAL" /><result column="goods_amount" property="goodsAmount" jdbcType="DECIMAL" /><result column="shipping_fee" property="shippingFee" jdbcType="DECIMAL" /><result column="order_amount" property="orderAmount" jdbcType="DECIMAL" /><result column="coupon_id" property="couponId" jdbcType="BIGINT" /><result column="coupon_paid" property="couponPaid" jdbcType="DECIMAL" /><result column="money_paid" property="moneyPaid" jdbcType="DECIMAL" /><result column="pay_amount" property="payAmount" jdbcType="DECIMAL" /><result column="add_time" property="addTime" jdbcType="TIMESTAMP" /><result column="confirm_time" property="confirmTime" jdbcType="TIMESTAMP" /><result column="pay_time" property="payTime" jdbcType="TIMESTAMP" /></resultMap><sql id="Example_Where_Clause" ><where ><foreach collection="oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Update_By_Example_Where_Clause" ><where ><foreach collection="example.oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Base_Column_List" >order_id, user_id, order_status, pay_status, shipping_status, address, consignee, goods_id, goods_number, goods_price, goods_amount, shipping_fee, order_amount, coupon_id, coupon_paid, money_paid, pay_amount, add_time, confirm_time, pay_time</sql><select id="selectByExample" resultMap="BaseResultMap" parameterType="com.itheima.shop.pojo.TradeOrderExample" >select<if test="distinct" >distinct</if><include refid="Base_Column_List" />from trade_order<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if><if test="orderByClause != null" >order by ${orderByClause}</if></select><select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >select <include refid="Base_Column_List" />from trade_orderwhere order_id = #{orderId,jdbcType=BIGINT}</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Long" >delete from trade_orderwhere order_id = #{orderId,jdbcType=BIGINT}</delete><delete id="deleteByExample" parameterType="com.itheima.shop.pojo.TradeOrderExample" >delete from trade_order<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></delete><insert id="insert" parameterType="com.itheima.shop.pojo.TradeOrder" >insert into trade_order (order_id, user_id, order_status, pay_status, shipping_status, address, consignee, goods_id, goods_number, goods_price, goods_amount, shipping_fee, order_amount, coupon_id, coupon_paid, money_paid, pay_amount, add_time, confirm_time, pay_time)values (#{orderId,jdbcType=BIGINT}, #{userId,jdbcType=BIGINT}, #{orderStatus,jdbcType=INTEGER}, #{payStatus,jdbcType=INTEGER}, #{shippingStatus,jdbcType=INTEGER}, #{address,jdbcType=VARCHAR}, #{consignee,jdbcType=VARCHAR}, #{goodsId,jdbcType=BIGINT}, #{goodsNumber,jdbcType=INTEGER}, #{goodsPrice,jdbcType=DECIMAL}, #{goodsAmount,jdbcType=DECIMAL}, #{shippingFee,jdbcType=DECIMAL}, #{orderAmount,jdbcType=DECIMAL}, #{couponId,jdbcType=BIGINT}, #{couponPaid,jdbcType=DECIMAL}, #{moneyPaid,jdbcType=DECIMAL}, #{payAmount,jdbcType=DECIMAL}, #{addTime,jdbcType=TIMESTAMP}, #{confirmTime,jdbcType=TIMESTAMP}, #{payTime,jdbcType=TIMESTAMP})</insert><insert id="insertSelective" parameterType="com.itheima.shop.pojo.TradeOrder" >insert into trade_order<trim prefix="(" suffix=")" suffixOverrides="," ><if test="orderId != null" >order_id,</if><if test="userId != null" >user_id,</if><if test="orderStatus != null" >order_status,</if><if test="payStatus != null" >pay_status,</if><if test="shippingStatus != null" >shipping_status,</if><if test="address != null" >address,</if><if test="consignee != null" >consignee,</if><if test="goodsId != null" >goods_id,</if><if test="goodsNumber != null" >goods_number,</if><if test="goodsPrice != null" >goods_price,</if><if test="goodsAmount != null" >goods_amount,</if><if test="shippingFee != null" >shipping_fee,</if><if test="orderAmount != null" >order_amount,</if><if test="couponId != null" >coupon_id,</if><if test="couponPaid != null" >coupon_paid,</if><if test="moneyPaid != null" >money_paid,</if><if test="payAmount != null" >pay_amount,</if><if test="addTime != null" >add_time,</if><if test="confirmTime != null" >confirm_time,</if><if test="payTime != null" >pay_time,</if></trim><trim prefix="values (" suffix=")" suffixOverrides="," ><if test="orderId != null" >#{orderId,jdbcType=BIGINT},</if><if test="userId != null" >#{userId,jdbcType=BIGINT},</if><if test="orderStatus != null" >#{orderStatus,jdbcType=INTEGER},</if><if test="payStatus != null" >#{payStatus,jdbcType=INTEGER},</if><if test="shippingStatus != null" >#{shippingStatus,jdbcType=INTEGER},</if><if test="address != null" >#{address,jdbcType=VARCHAR},</if><if test="consignee != null" >#{consignee,jdbcType=VARCHAR},</if><if test="goodsId != null" >#{goodsId,jdbcType=BIGINT},</if><if test="goodsNumber != null" >#{goodsNumber,jdbcType=INTEGER},</if><if test="goodsPrice != null" >#{goodsPrice,jdbcType=DECIMAL},</if><if test="goodsAmount != null" >#{goodsAmount,jdbcType=DECIMAL},</if><if test="shippingFee != null" >#{shippingFee,jdbcType=DECIMAL},</if><if test="orderAmount != null" >#{orderAmount,jdbcType=DECIMAL},</if><if test="couponId != null" >#{couponId,jdbcType=BIGINT},</if><if test="couponPaid != null" >#{couponPaid,jdbcType=DECIMAL},</if><if test="moneyPaid != null" >#{moneyPaid,jdbcType=DECIMAL},</if><if test="payAmount != null" >#{payAmount,jdbcType=DECIMAL},</if><if test="addTime != null" >#{addTime,jdbcType=TIMESTAMP},</if><if test="confirmTime != null" >#{confirmTime,jdbcType=TIMESTAMP},</if><if test="payTime != null" >#{payTime,jdbcType=TIMESTAMP},</if></trim></insert><select id="countByExample" parameterType="com.itheima.shop.pojo.TradeOrderExample" resultType="java.lang.Integer" >select count(*) from trade_order<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></select><update id="updateByExampleSelective" parameterType="map" >update trade_order<set ><if test="record.orderId != null" >order_id = #{record.orderId,jdbcType=BIGINT},</if><if test="record.userId != null" >user_id = #{record.userId,jdbcType=BIGINT},</if><if test="record.orderStatus != null" >order_status = #{record.orderStatus,jdbcType=INTEGER},</if><if test="record.payStatus != null" >pay_status = #{record.payStatus,jdbcType=INTEGER},</if><if test="record.shippingStatus != null" >shipping_status = #{record.shippingStatus,jdbcType=INTEGER},</if><if test="record.address != null" >address = #{record.address,jdbcType=VARCHAR},</if><if test="record.consignee != null" >consignee = #{record.consignee,jdbcType=VARCHAR},</if><if test="record.goodsId != null" >goods_id = #{record.goodsId,jdbcType=BIGINT},</if><if test="record.goodsNumber != null" >goods_number = #{record.goodsNumber,jdbcType=INTEGER},</if><if test="record.goodsPrice != null" >goods_price = #{record.goodsPrice,jdbcType=DECIMAL},</if><if test="record.goodsAmount != null" >goods_amount = #{record.goodsAmount,jdbcType=DECIMAL},</if><if test="record.shippingFee != null" >shipping_fee = #{record.shippingFee,jdbcType=DECIMAL},</if><if test="record.orderAmount != null" >order_amount = #{record.orderAmount,jdbcType=DECIMAL},</if><if test="record.couponId != null" >coupon_id = #{record.couponId,jdbcType=BIGINT},</if><if test="record.couponPaid != null" >coupon_paid = #{record.couponPaid,jdbcType=DECIMAL},</if><if test="record.moneyPaid != null" >money_paid = #{record.moneyPaid,jdbcType=DECIMAL},</if><if test="record.payAmount != null" >pay_amount = #{record.payAmount,jdbcType=DECIMAL},</if><if test="record.addTime != null" >add_time = #{record.addTime,jdbcType=TIMESTAMP},</if><if test="record.confirmTime != null" >confirm_time = #{record.confirmTime,jdbcType=TIMESTAMP},</if><if test="record.payTime != null" >pay_time = #{record.payTime,jdbcType=TIMESTAMP},</if></set><if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByExample" parameterType="map" >update trade_orderset order_id = #{record.orderId,jdbcType=BIGINT},user_id = #{record.userId,jdbcType=BIGINT},order_status = #{record.orderStatus,jdbcType=INTEGER},pay_status = #{record.payStatus,jdbcType=INTEGER},shipping_status = #{record.shippingStatus,jdbcType=INTEGER},address = #{record.address,jdbcType=VARCHAR},consignee = #{record.consignee,jdbcType=VARCHAR},goods_id = #{record.goodsId,jdbcType=BIGINT},goods_number = #{record.goodsNumber,jdbcType=INTEGER},goods_price = #{record.goodsPrice,jdbcType=DECIMAL},goods_amount = #{record.goodsAmount,jdbcType=DECIMAL},shipping_fee = #{record.shippingFee,jdbcType=DECIMAL},order_amount = #{record.orderAmount,jdbcType=DECIMAL},coupon_id = #{record.couponId,jdbcType=BIGINT},coupon_paid = #{record.couponPaid,jdbcType=DECIMAL},money_paid = #{record.moneyPaid,jdbcType=DECIMAL},pay_amount = #{record.payAmount,jdbcType=DECIMAL},add_time = #{record.addTime,jdbcType=TIMESTAMP},confirm_time = #{record.confirmTime,jdbcType=TIMESTAMP},pay_time = #{record.payTime,jdbcType=TIMESTAMP}<if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByPrimaryKeySelective" parameterType="com.itheima.shop.pojo.TradeOrder" >update trade_order<set ><if test="userId != null" >user_id = #{userId,jdbcType=BIGINT},</if><if test="orderStatus != null" >order_status = #{orderStatus,jdbcType=INTEGER},</if><if test="payStatus != null" >pay_status = #{payStatus,jdbcType=INTEGER},</if><if test="shippingStatus != null" >shipping_status = #{shippingStatus,jdbcType=INTEGER},</if><if test="address != null" >address = #{address,jdbcType=VARCHAR},</if><if test="consignee != null" >consignee = #{consignee,jdbcType=VARCHAR},</if><if test="goodsId != null" >goods_id = #{goodsId,jdbcType=BIGINT},</if><if test="goodsNumber != null" >goods_number = #{goodsNumber,jdbcType=INTEGER},</if><if test="goodsPrice != null" >goods_price = #{goodsPrice,jdbcType=DECIMAL},</if><if test="goodsAmount != null" >goods_amount = #{goodsAmount,jdbcType=DECIMAL},</if><if test="shippingFee != null" >shipping_fee = #{shippingFee,jdbcType=DECIMAL},</if><if test="orderAmount != null" >order_amount = #{orderAmount,jdbcType=DECIMAL},</if><if test="couponId != null" >coupon_id = #{couponId,jdbcType=BIGINT},</if><if test="couponPaid != null" >coupon_paid = #{couponPaid,jdbcType=DECIMAL},</if><if test="moneyPaid != null" >money_paid = #{moneyPaid,jdbcType=DECIMAL},</if><if test="payAmount != null" >pay_amount = #{payAmount,jdbcType=DECIMAL},</if><if test="addTime != null" >add_time = #{addTime,jdbcType=TIMESTAMP},</if><if test="confirmTime != null" >confirm_time = #{confirmTime,jdbcType=TIMESTAMP},</if><if test="payTime != null" >pay_time = #{payTime,jdbcType=TIMESTAMP},</if></set>where order_id = #{orderId,jdbcType=BIGINT}</update><update id="updateByPrimaryKey" parameterType="com.itheima.shop.pojo.TradeOrder" >update trade_orderset user_id = #{userId,jdbcType=BIGINT},order_status = #{orderStatus,jdbcType=INTEGER},pay_status = #{payStatus,jdbcType=INTEGER},shipping_status = #{shippingStatus,jdbcType=INTEGER},address = #{address,jdbcType=VARCHAR},consignee = #{consignee,jdbcType=VARCHAR},goods_id = #{goodsId,jdbcType=BIGINT},goods_number = #{goodsNumber,jdbcType=INTEGER},goods_price = #{goodsPrice,jdbcType=DECIMAL},goods_amount = #{goodsAmount,jdbcType=DECIMAL},shipping_fee = #{shippingFee,jdbcType=DECIMAL},order_amount = #{orderAmount,jdbcType=DECIMAL},coupon_id = #{couponId,jdbcType=BIGINT},coupon_paid = #{couponPaid,jdbcType=DECIMAL},money_paid = #{moneyPaid,jdbcType=DECIMAL},pay_amount = #{payAmount,jdbcType=DECIMAL},add_time = #{addTime,jdbcType=TIMESTAMP},confirm_time = #{confirmTime,jdbcType=TIMESTAMP},pay_time = #{payTime,jdbcType=TIMESTAMP}where order_id = #{orderId,jdbcType=BIGINT}</update>
</mapper>
6.8、创建 文件 application.properties
# dubbo
spring.application.name=dubbo-order-provider
spring.dubbo.application.id=dubbo-order-provider
spring.dubbo.application.name=dubbo-order-provider
spring.dubbo.registry.address=zookeeper://192.168.25.140:2181;zookeeper://192.168.25.140:2182;zookeeper://192.168.25.140:2183
spring.dubbo.server=true
spring.dubbo.protocol.name=dubbo
spring.dubbo.protocol.port=20884# DB
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/trade?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root# Mybatis
#pojo别名扫描包
mybatis.type-aliases-package=com.itheima.shop.pojo
#加载Mybatis映射文件
mybatis.mapper-locations=classpath:com/itheima/shop/mapper/*Mapper.xml# RocketMQ
# 下单失败消息发送组
rocketmq.name-server=192.168.25.135:9876;192.168.25.138:9876
rocketmq.producer.group=orderProducerGroupmq.order.consumer.group.name=order_orderTopic_cancel_group
mq.order.topic=orderTopic
mq.order.tag.cancel=order_cancelmq.pay.topic=payTopic
mq.pay.consumer.group.name=pay_payTopic_group
6.9 创建 测试类 OrderServiceTest.java
package com.itheima.test;import com.itheima.api.IOrderService;
import com.itheima.shop.OrderServiceApplication;
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.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.io.IOException;
import java.math.BigDecimal;@RunWith(SpringRunner.class)
@SpringBootTest(classes = OrderServiceApplication.class)
public class OrderServiceTest {@Autowiredprivate IOrderService orderService;@Testpublic void confirmOrder() throws IOException {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));orderService.confirmOrder(order);System.in.read();}}

7、创建 shop-pay-service 支付服务 工程。

7.1、在 pom.xml 中,导入依赖坐标。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>shop-parent</artifactId><groupId>com.iteima.shop</groupId><version>1.0-SNAPSHOT</version><relativePath>../shop-parent/pom.xml</relativePath></parent><modelVersion>4.0.0</modelVersion><artifactId>shop-pay-service</artifactId><dependencies><!--mybatis-springboot--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.1</version></dependency><!-- MySQL连接驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--common--><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-common</artifactId><version>1.0-SNAPSHOT</version></dependency><!--接口--><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-api</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-pojo</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
<!-- D:\java-test\idea2019\shop\shop-pay-service\pom.xml -->
7.2、创建 接口 类 TradeMqProducerTempMapper.java
package com.itheima.shop.mapper;import com.itheima.shop.pojo.TradeMqProducerTemp;
import com.itheima.shop.pojo.TradeMqProducerTempExample;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper
public interface TradeMqProducerTempMapper {int countByExample(TradeMqProducerTempExample example);int deleteByExample(TradeMqProducerTempExample example);int deleteByPrimaryKey(String id);int insert(TradeMqProducerTemp record);int insertSelective(TradeMqProducerTemp record);List<TradeMqProducerTemp> selectByExample(TradeMqProducerTempExample example);TradeMqProducerTemp selectByPrimaryKey(String id);int updateByExampleSelective(@Param("record") TradeMqProducerTemp record, @Param("example") TradeMqProducerTempExample example);int updateByExample(@Param("record") TradeMqProducerTemp record, @Param("example") TradeMqProducerTempExample example);int updateByPrimaryKeySelective(TradeMqProducerTemp record);int updateByPrimaryKey(TradeMqProducerTemp record);
}
7.3、创建 接口 类 TradePayMapper.java
package com.itheima.shop.mapper;import com.itheima.shop.pojo.TradePay;
import com.itheima.shop.pojo.TradePayExample;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;
@Mapper
public interface TradePayMapper {int countByExample(TradePayExample example);int deleteByExample(TradePayExample example);int deleteByPrimaryKey(Long payId);int insert(TradePay record);int insertSelective(TradePay record);List<TradePay> selectByExample(TradePayExample example);TradePay selectByPrimaryKey(Long payId);int updateByExampleSelective(@Param("record") TradePay record, @Param("example") TradePayExample example);int updateByExample(@Param("record") TradePay record, @Param("example") TradePayExample example);int updateByPrimaryKeySelective(TradePay record);int updateByPrimaryKey(TradePay record);
}
7.4、创建 类 PayServiceImpl.java
package com.itheima.shop.service.impl;import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.itheima.api.IPayService;
import com.itheima.constant.ShopCode;
import com.itheima.entity.Result;
import com.itheima.exception.CastException;
import com.itheima.shop.mapper.TradeMqProducerTempMapper;
import com.itheima.shop.mapper.TradePayMapper;
import com.itheima.shop.pojo.TradeMqProducerTemp;
import com.itheima.shop.pojo.TradePay;
import com.itheima.shop.pojo.TradePayExample;
import com.itheima.utils.IDWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;import java.util.Date;@Slf4j
@Component
@Service(interfaceClass = IPayService.class)
public class PayServiceImpl implements IPayService{@Autowiredprivate TradePayMapper tradePayMapper;@Autowiredprivate TradeMqProducerTempMapper mqProducerTempMapper;@Autowiredprivate ThreadPoolTaskExecutor threadPoolTaskExecutor;@Autowiredprivate RocketMQTemplate rocketMQTemplate;@Autowiredprivate IDWorker idWorker;@Value("${rocketmq.producer.group}")private String groupName;@Value("${mq.topic}")private String topic;@Value("${mq.pay.tag}")private String tag;@Overridepublic Result createPayment(TradePay tradePay) {if(tradePay==null || tradePay.getOrderId()==null){CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);}//1.判断订单支付状态TradePayExample example = new TradePayExample();TradePayExample.Criteria criteria = example.createCriteria();criteria.andOrderIdEqualTo(tradePay.getOrderId());criteria.andIsPaidEqualTo(ShopCode.SHOP_PAYMENT_IS_PAID.getCode());int r = tradePayMapper.countByExample(example);if(r>0){CastException.cast(ShopCode.SHOP_PAYMENT_IS_PAID);}//2.设置订单的状态为未支付tradePay.setIsPaid(ShopCode.SHOP_ORDER_PAY_STATUS_NO_PAY.getCode());//3.保存支付订单tradePay.setPayId(idWorker.nextId());tradePayMapper.insert(tradePay);return new Result(ShopCode.SHOP_SUCCESS.getSuccess(),ShopCode.SHOP_SUCCESS.getMessage());}@Overridepublic Result callbackPayment(TradePay tradePay) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {log.info("支付回调");//1. 判断用户支付状态if(tradePay.getIsPaid().intValue()==ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode().intValue()){//2. 更新支付订单状态为已支付Long payId = tradePay.getPayId();TradePay pay = tradePayMapper.selectByPrimaryKey(payId);//判断支付订单是否存在if(pay==null){CastException.cast(ShopCode.SHOP_PAYMENT_NOT_FOUND);}pay.setIsPaid(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode());int r = tradePayMapper.updateByPrimaryKeySelective(pay);log.info("支付订单状态改为已支付");if(r==1){//3. 创建支付成功的消息TradeMqProducerTemp tradeMqProducerTemp = new TradeMqProducerTemp();tradeMqProducerTemp.setId(String.valueOf(idWorker.nextId()));tradeMqProducerTemp.setGroupName(groupName);tradeMqProducerTemp.setMsgTopic(topic);tradeMqProducerTemp.setMsgTag(tag);tradeMqProducerTemp.setMsgKey(String.valueOf(tradePay.getPayId()));tradeMqProducerTemp.setMsgBody(JSON.toJSONString(tradePay));tradeMqProducerTemp.setCreateTime(new Date());//4. 将消息持久化数据库mqProducerTempMapper.insert(tradeMqProducerTemp);log.info("将支付成功消息持久化到数据库");//在线程池中进行处理threadPoolTaskExecutor.submit(new Runnable() {@Overridepublic void run() {//5. 发送消息到MQSendResult result = null;try {result = sendMessage(topic, tag, String.valueOf(tradePay.getPayId()), JSON.toJSONString(tradePay));} catch (Exception e) {e.printStackTrace();}if(result.getSendStatus().equals(SendStatus.SEND_OK)){log.info("消息发送成功");//6. 等待发送结果,如果MQ接受到消息,删除发送成功的消息mqProducerTempMapper.deleteByPrimaryKey(tradeMqProducerTemp.getId());log.info("持久化到数据库的消息删除");}}});}return new Result(ShopCode.SHOP_SUCCESS.getSuccess(),ShopCode.SHOP_SUCCESS.getMessage());}else{CastException.cast(ShopCode.SHOP_PAYMENT_PAY_ERROR);return new Result(ShopCode.SHOP_FAIL.getSuccess(),ShopCode.SHOP_FAIL.getMessage());}}/*** 发送支付成功消息* @param topic* @param tag* @param key* @param body*/private SendResult sendMessage(String topic, String tag, String key, String body) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {if(StringUtils.isEmpty(topic)){CastException.cast(ShopCode.SHOP_MQ_TOPIC_IS_EMPTY);}if(StringUtils.isEmpty(body)){CastException.cast(ShopCode.SHOP_MQ_MESSAGE_BODY_IS_EMPTY);}Message message = new Message(topic,tag,key,body.getBytes());SendResult sendResult = rocketMQTemplate.getProducer().send(message);return sendResult;}
}
7.5、创建 类 PayServiceApplication.java
package com.itheima.shop;import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import com.itheima.utils.IDWorker;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;@SpringBootApplication
@EnableDubboConfiguration
public class PayServiceApplication {public static void main(String[] args) {SpringApplication.run(PayServiceApplication.class,args);}@Beanpublic IDWorker getBean(){return new IDWorker(1,2);}@Beanpublic ThreadPoolTaskExecutor getThreadPool() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(4);executor.setMaxPoolSize(8);executor.setQueueCapacity(100);executor.setKeepAliveSeconds(60);executor.setThreadNamePrefix("Pool-A");executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}}
7.6、创建 文件 TradeMqProducerTempMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.itheima.shop.mapper.TradeMqProducerTempMapper" ><resultMap id="BaseResultMap" type="com.itheima.shop.pojo.TradeMqProducerTemp" ><id column="id" property="id" jdbcType="VARCHAR" /><result column="group_name" property="groupName" jdbcType="VARCHAR" /><result column="msg_topic" property="msgTopic" jdbcType="VARCHAR" /><result column="msg_tag" property="msgTag" jdbcType="VARCHAR" /><result column="msg_key" property="msgKey" jdbcType="VARCHAR" /><result column="msg_body" property="msgBody" jdbcType="VARCHAR" /><result column="msg_status" property="msgStatus" jdbcType="INTEGER" /><result column="create_time" property="createTime" jdbcType="TIMESTAMP" /></resultMap><sql id="Example_Where_Clause" ><where ><foreach collection="oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Update_By_Example_Where_Clause" ><where ><foreach collection="example.oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Base_Column_List" >id, group_name, msg_topic, msg_tag, msg_key, msg_body, msg_status, create_time</sql><select id="selectByExample" resultMap="BaseResultMap" parameterType="com.itheima.shop.pojo.TradeMqProducerTempExample" >select<if test="distinct" >distinct</if><include refid="Base_Column_List" />from trade_mq_producer_temp<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if><if test="orderByClause != null" >order by ${orderByClause}</if></select><select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" >select <include refid="Base_Column_List" />from trade_mq_producer_tempwhere id = #{id,jdbcType=VARCHAR}</select><delete id="deleteByPrimaryKey" parameterType="java.lang.String" >delete from trade_mq_producer_tempwhere id = #{id,jdbcType=VARCHAR}</delete><delete id="deleteByExample" parameterType="com.itheima.shop.pojo.TradeMqProducerTempExample" >delete from trade_mq_producer_temp<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></delete><insert id="insert" parameterType="com.itheima.shop.pojo.TradeMqProducerTemp" >insert into trade_mq_producer_temp (id, group_name, msg_topic, msg_tag, msg_key, msg_body, msg_status, create_time)values (#{id,jdbcType=VARCHAR}, #{groupName,jdbcType=VARCHAR}, #{msgTopic,jdbcType=VARCHAR}, #{msgTag,jdbcType=VARCHAR}, #{msgKey,jdbcType=VARCHAR}, #{msgBody,jdbcType=VARCHAR}, #{msgStatus,jdbcType=INTEGER}, #{createTime,jdbcType=TIMESTAMP})</insert><insert id="insertSelective" parameterType="com.itheima.shop.pojo.TradeMqProducerTemp" >insert into trade_mq_producer_temp<trim prefix="(" suffix=")" suffixOverrides="," ><if test="id != null" >id,</if><if test="groupName != null" >group_name,</if><if test="msgTopic != null" >msg_topic,</if><if test="msgTag != null" >msg_tag,</if><if test="msgKey != null" >msg_key,</if><if test="msgBody != null" >msg_body,</if><if test="msgStatus != null" >msg_status,</if><if test="createTime != null" >create_time,</if></trim><trim prefix="values (" suffix=")" suffixOverrides="," ><if test="id != null" >#{id,jdbcType=VARCHAR},</if><if test="groupName != null" >#{groupName,jdbcType=VARCHAR},</if><if test="msgTopic != null" >#{msgTopic,jdbcType=VARCHAR},</if><if test="msgTag != null" >#{msgTag,jdbcType=VARCHAR},</if><if test="msgKey != null" >#{msgKey,jdbcType=VARCHAR},</if><if test="msgBody != null" >#{msgBody,jdbcType=VARCHAR},</if><if test="msgStatus != null" >#{msgStatus,jdbcType=INTEGER},</if><if test="createTime != null" >#{createTime,jdbcType=TIMESTAMP},</if></trim></insert><select id="countByExample" parameterType="com.itheima.shop.pojo.TradeMqProducerTempExample" resultType="java.lang.Integer" >select count(*) from trade_mq_producer_temp<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></select><update id="updateByExampleSelective" parameterType="map" >update trade_mq_producer_temp<set ><if test="record.id != null" >id = #{record.id,jdbcType=VARCHAR},</if><if test="record.groupName != null" >group_name = #{record.groupName,jdbcType=VARCHAR},</if><if test="record.msgTopic != null" >msg_topic = #{record.msgTopic,jdbcType=VARCHAR},</if><if test="record.msgTag != null" >msg_tag = #{record.msgTag,jdbcType=VARCHAR},</if><if test="record.msgKey != null" >msg_key = #{record.msgKey,jdbcType=VARCHAR},</if><if test="record.msgBody != null" >msg_body = #{record.msgBody,jdbcType=VARCHAR},</if><if test="record.msgStatus != null" >msg_status = #{record.msgStatus,jdbcType=INTEGER},</if><if test="record.createTime != null" >create_time = #{record.createTime,jdbcType=TIMESTAMP},</if></set><if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByExample" parameterType="map" >update trade_mq_producer_tempset id = #{record.id,jdbcType=VARCHAR},group_name = #{record.groupName,jdbcType=VARCHAR},msg_topic = #{record.msgTopic,jdbcType=VARCHAR},msg_tag = #{record.msgTag,jdbcType=VARCHAR},msg_key = #{record.msgKey,jdbcType=VARCHAR},msg_body = #{record.msgBody,jdbcType=VARCHAR},msg_status = #{record.msgStatus,jdbcType=INTEGER},create_time = #{record.createTime,jdbcType=TIMESTAMP}<if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByPrimaryKeySelective" parameterType="com.itheima.shop.pojo.TradeMqProducerTemp" >update trade_mq_producer_temp<set ><if test="groupName != null" >group_name = #{groupName,jdbcType=VARCHAR},</if><if test="msgTopic != null" >msg_topic = #{msgTopic,jdbcType=VARCHAR},</if><if test="msgTag != null" >msg_tag = #{msgTag,jdbcType=VARCHAR},</if><if test="msgKey != null" >msg_key = #{msgKey,jdbcType=VARCHAR},</if><if test="msgBody != null" >msg_body = #{msgBody,jdbcType=VARCHAR},</if><if test="msgStatus != null" >msg_status = #{msgStatus,jdbcType=INTEGER},</if><if test="createTime != null" >create_time = #{createTime,jdbcType=TIMESTAMP},</if></set>where id = #{id,jdbcType=VARCHAR}</update><update id="updateByPrimaryKey" parameterType="com.itheima.shop.pojo.TradeMqProducerTemp" >update trade_mq_producer_tempset group_name = #{groupName,jdbcType=VARCHAR},msg_topic = #{msgTopic,jdbcType=VARCHAR},msg_tag = #{msgTag,jdbcType=VARCHAR},msg_key = #{msgKey,jdbcType=VARCHAR},msg_body = #{msgBody,jdbcType=VARCHAR},msg_status = #{msgStatus,jdbcType=INTEGER},create_time = #{createTime,jdbcType=TIMESTAMP}where id = #{id,jdbcType=VARCHAR}</update>
</mapper>
7.7、创建 文件 TradePayMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.itheima.shop.mapper.TradePayMapper" ><resultMap id="BaseResultMap" type="com.itheima.shop.pojo.TradePay" ><id column="pay_id" property="payId" jdbcType="BIGINT" /><result column="order_id" property="orderId" jdbcType="BIGINT" /><result column="pay_amount" property="payAmount" jdbcType="DECIMAL" /><result column="is_paid" property="isPaid" jdbcType="INTEGER" /></resultMap><sql id="Example_Where_Clause" ><where ><foreach collection="oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Update_By_Example_Where_Clause" ><where ><foreach collection="example.oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Base_Column_List" >pay_id, order_id, pay_amount, is_paid</sql><select id="selectByExample" resultMap="BaseResultMap" parameterType="com.itheima.shop.pojo.TradePayExample" >select<if test="distinct" >distinct</if><include refid="Base_Column_List" />from trade_pay<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if><if test="orderByClause != null" >order by ${orderByClause}</if></select><select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >select <include refid="Base_Column_List" />from trade_paywhere pay_id = #{payId,jdbcType=BIGINT}</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Long" >delete from trade_paywhere pay_id = #{payId,jdbcType=BIGINT}</delete><delete id="deleteByExample" parameterType="com.itheima.shop.pojo.TradePayExample" >delete from trade_pay<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></delete><insert id="insert" parameterType="com.itheima.shop.pojo.TradePay" >insert into trade_pay (pay_id, order_id, pay_amount, is_paid)values (#{payId,jdbcType=BIGINT}, #{orderId,jdbcType=BIGINT}, #{payAmount,jdbcType=DECIMAL}, #{isPaid,jdbcType=INTEGER})</insert><insert id="insertSelective" parameterType="com.itheima.shop.pojo.TradePay" >insert into trade_pay<trim prefix="(" suffix=")" suffixOverrides="," ><if test="payId != null" >pay_id,</if><if test="orderId != null" >order_id,</if><if test="payAmount != null" >pay_amount,</if><if test="isPaid != null" >is_paid,</if></trim><trim prefix="values (" suffix=")" suffixOverrides="," ><if test="payId != null" >#{payId,jdbcType=BIGINT},</if><if test="orderId != null" >#{orderId,jdbcType=BIGINT},</if><if test="payAmount != null" >#{payAmount,jdbcType=DECIMAL},</if><if test="isPaid != null" >#{isPaid,jdbcType=INTEGER},</if></trim></insert><select id="countByExample" parameterType="com.itheima.shop.pojo.TradePayExample" resultType="java.lang.Integer" >select count(*) from trade_pay<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></select><update id="updateByExampleSelective" parameterType="map" >update trade_pay<set ><if test="record.payId != null" >pay_id = #{record.payId,jdbcType=BIGINT},</if><if test="record.orderId != null" >order_id = #{record.orderId,jdbcType=BIGINT},</if><if test="record.payAmount != null" >pay_amount = #{record.payAmount,jdbcType=DECIMAL},</if><if test="record.isPaid != null" >is_paid = #{record.isPaid,jdbcType=INTEGER},</if></set><if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByExample" parameterType="map" >update trade_payset pay_id = #{record.payId,jdbcType=BIGINT},order_id = #{record.orderId,jdbcType=BIGINT},pay_amount = #{record.payAmount,jdbcType=DECIMAL},is_paid = #{record.isPaid,jdbcType=INTEGER}<if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByPrimaryKeySelective" parameterType="com.itheima.shop.pojo.TradePay" >update trade_pay<set ><if test="orderId != null" >order_id = #{orderId,jdbcType=BIGINT},</if><if test="payAmount != null" >pay_amount = #{payAmount,jdbcType=DECIMAL},</if><if test="isPaid != null" >is_paid = #{isPaid,jdbcType=INTEGER},</if></set>where pay_id = #{payId,jdbcType=BIGINT}</update><update id="updateByPrimaryKey" parameterType="com.itheima.shop.pojo.TradePay" >update trade_payset order_id = #{orderId,jdbcType=BIGINT},pay_amount = #{payAmount,jdbcType=DECIMAL},is_paid = #{isPaid,jdbcType=INTEGER}where pay_id = #{payId,jdbcType=BIGINT}</update>
</mapper>
7.8、创建 文件 application.properties
# dubbo
spring.application.name=dubbo-pay-provider
spring.dubbo.application.id=dubbo-pay-provider
spring.dubbo.application.name=dubbo-pay-provider
spring.dubbo.registry.address=zookeeper://192.168.25.140:2181;zookeeper://192.168.25.140:2182;zookeeper://192.168.25.140:2183
spring.dubbo.server=true
spring.dubbo.protocol.name=dubbo
spring.dubbo.protocol.port=20885# DB
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/trade?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root# Mybatis
#pojo别名扫描包
mybatis.type-aliases-package=com.itheima.shop.pojo
#加载Mybatis映射文件
mybatis.mapper-locations=classpath:com/itheima/shop/mapper/*Mapper.xml# RocketMQ
rocketmq.name-server=192.168.25.135:9876;192.168.25.138:9876
rocketmq.producer.group=payProducerGroupmq.topic=payTopic
mq.pay.tag=paid
7.9 创建 测试类 PayServiceTest.java
package com.itheima.test;import com.itheima.api.IPayService;
import com.itheima.constant.ShopCode;
import com.itheima.shop.PayServiceApplication;
import com.itheima.shop.pojo.TradePay;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.io.IOException;
import java.math.BigDecimal;@RunWith(SpringRunner.class)
@SpringBootTest(classes = PayServiceApplication.class)
public class PayServiceTest {@Autowiredprivate IPayService payService;@Testpublic void createPayment(){long orderId = 351526299216515072L;TradePay tradePay = new TradePay();tradePay.setOrderId(orderId);tradePay.setPayAmount(new BigDecimal(880));payService.createPayment(tradePay);}@Testpublic void callbackPayment() throws InterruptedException, RemotingException, MQClientException, MQBrokerException, IOException {long payId = 352516176372441088L;long orderId = 351526299216515072L;TradePay tradePay = new TradePay();tradePay.setPayId(payId);tradePay.setOrderId(orderId);tradePay.setIsPaid(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode());payService.callbackPayment(tradePay);System.in.read();}}

8、创建 shop-user-service 用户服务 工程。

8.1、在 pom.xml 中,导入依赖坐标。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>shop-parent</artifactId><groupId>com.iteima.shop</groupId><version>1.0-SNAPSHOT</version><relativePath>../shop-parent/pom.xml</relativePath></parent><modelVersion>4.0.0</modelVersion><artifactId>shop-user-service</artifactId><dependencies><!--mybatis-springboot--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.1</version></dependency><!-- MySQL连接驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-api</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-common</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-pojo</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
<!-- D:\java-test\idea2019\shop\shop-user-service\pom.xml -->
8.2、创建 接口 类 TradeUserMapper.java
package com.itheima.shop.mapper;import com.itheima.shop.pojo.TradeUser;
import com.itheima.shop.pojo.TradeUserExample;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper
public interface TradeUserMapper {int countByExample(TradeUserExample example);int deleteByExample(TradeUserExample example);int deleteByPrimaryKey(Long userId);int insert(TradeUser record);int insertSelective(TradeUser record);List<TradeUser> selectByExample(TradeUserExample example);TradeUser selectByPrimaryKey(Long userId);int updateByExampleSelective(@Param("record") TradeUser record, @Param("example") TradeUserExample example);int updateByExample(@Param("record") TradeUser record, @Param("example") TradeUserExample example);int updateByPrimaryKeySelective(TradeUser record);int updateByPrimaryKey(TradeUser record);
}
8.3、创建 接口 类 TradeUserMoneyLogMapper.java
package com.itheima.shop.mapper;import com.itheima.shop.pojo.TradeUserMoneyLog;
import com.itheima.shop.pojo.TradeUserMoneyLogExample;
import com.itheima.shop.pojo.TradeUserMoneyLogKey;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper
public interface TradeUserMoneyLogMapper {int countByExample(TradeUserMoneyLogExample example);int deleteByExample(TradeUserMoneyLogExample example);int deleteByPrimaryKey(TradeUserMoneyLogKey key);int insert(TradeUserMoneyLog record);int insertSelective(TradeUserMoneyLog record);List<TradeUserMoneyLog> selectByExample(TradeUserMoneyLogExample example);TradeUserMoneyLog selectByPrimaryKey(TradeUserMoneyLogKey key);int updateByExampleSelective(@Param("record") TradeUserMoneyLog record, @Param("example") TradeUserMoneyLogExample example);int updateByExample(@Param("record") TradeUserMoneyLog record, @Param("example") TradeUserMoneyLogExample example);int updateByPrimaryKeySelective(TradeUserMoneyLog record);int updateByPrimaryKey(TradeUserMoneyLog record);
}
8.4、创建 类 CancelMQListener.java
package com.itheima.shop.mq;import com.alibaba.fastjson.JSON;
import com.itheima.api.IUserService;
import com.itheima.constant.ShopCode;
import com.itheima.entity.MQEntity;
import com.itheima.shop.pojo.TradeUserMoneyLog;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;@Slf4j
@Component
@RocketMQMessageListener(topic = "${mq.order.topic}",consumerGroup = "${mq.order.consumer.group.name}",messageModel = MessageModel.BROADCASTING )
public class CancelMQListener implements RocketMQListener<MessageExt>{@Autowiredprivate IUserService userService;@Overridepublic void onMessage(MessageExt messageExt) {try {//1.解析消息String body = new String(messageExt.getBody(), "UTF-8");MQEntity mqEntity = JSON.parseObject(body, MQEntity.class);log.info("接收到消息");if(mqEntity.getUserMoney()!=null && mqEntity.getUserMoney().compareTo(BigDecimal.ZERO)>0){//2.调用业务层,进行余额修改TradeUserMoneyLog userMoneyLog = new TradeUserMoneyLog();userMoneyLog.setUseMoney(mqEntity.getUserMoney());userMoneyLog.setMoneyLogType(ShopCode.SHOP_USER_MONEY_REFUND.getCode());userMoneyLog.setUserId(mqEntity.getUserId());userMoneyLog.setOrderId(mqEntity.getOrderId());userService.updateMoneyPaid(userMoneyLog);log.info("余额回退成功");}} catch (UnsupportedEncodingException e) {e.printStackTrace();log.error("余额回退失败");}}
}
8.5、创建 类 UserServiceImpl.java
package com.itheima.shop.service.impl;import com.alibaba.dubbo.config.annotation.Service;
import com.itheima.api.IUserService;
import com.itheima.constant.ShopCode;
import com.itheima.entity.Result;
import com.itheima.exception.CastException;
import com.itheima.shop.mapper.TradeUserMapper;
import com.itheima.shop.mapper.TradeUserMoneyLogMapper;
import com.itheima.shop.pojo.TradeUser;
import com.itheima.shop.pojo.TradeUserMoneyLog;
import com.itheima.shop.pojo.TradeUserMoneyLogExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.math.BigDecimal;
import java.util.Date;@Component
@Service(interfaceClass = IUserService.class)
public class UserServiceImpl implements IUserService{@Autowiredprivate TradeUserMapper userMapper;@Autowiredprivate TradeUserMoneyLogMapper userMoneyLogMapper;@Overridepublic TradeUser findOne(Long userId) {if(userId==null){CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);}return userMapper.selectByPrimaryKey(userId);}@Overridepublic Result updateMoneyPaid(TradeUserMoneyLog userMoneyLog) {//1.校验参数是否合法if(userMoneyLog==null ||userMoneyLog.getUserId()==null ||userMoneyLog.getOrderId()==null ||userMoneyLog.getUseMoney()==null||userMoneyLog.getUseMoney().compareTo(BigDecimal.ZERO)<=0){CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);}//2.查询订单余额使用日志TradeUserMoneyLogExample userMoneyLogExample = new TradeUserMoneyLogExample();TradeUserMoneyLogExample.Criteria criteria = userMoneyLogExample.createCriteria();criteria.andOrderIdEqualTo(userMoneyLog.getOrderId());criteria.andUserIdEqualTo(userMoneyLog.getUserId());int r = userMoneyLogMapper.countByExample(userMoneyLogExample);TradeUser tradeUser = userMapper.selectByPrimaryKey(userMoneyLog.getUserId());//3.扣减余额...if(userMoneyLog.getMoneyLogType().intValue()==ShopCode.SHOP_USER_MONEY_PAID.getCode().intValue()){if(r>0){//已经付款CastException.cast(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY);}//减余额tradeUser.setUserMoney(new BigDecimal(tradeUser.getUserMoney()).subtract(userMoneyLog.getUseMoney()).longValue());userMapper.updateByPrimaryKey(tradeUser);}//4.回退余额...if(userMoneyLog.getMoneyLogType().intValue()==ShopCode.SHOP_USER_MONEY_REFUND.getCode().intValue()){if(r<0){//如果没有支付,则不能回退余额CastException.cast(ShopCode.SHOP_ORDER_PAY_STATUS_NO_PAY);}//防止多次退款TradeUserMoneyLogExample userMoneyLogExample2 = new TradeUserMoneyLogExample();TradeUserMoneyLogExample.Criteria criteria1 = userMoneyLogExample2.createCriteria();criteria1.andOrderIdEqualTo(userMoneyLog.getOrderId());criteria1.andUserIdEqualTo(userMoneyLog.getUserId());criteria1.andMoneyLogTypeEqualTo(ShopCode.SHOP_USER_MONEY_REFUND.getCode());int r2 = userMoneyLogMapper.countByExample(userMoneyLogExample2);if(r2>0){CastException.cast(ShopCode.SHOP_USER_MONEY_REFUND_ALREADY);}//退款tradeUser.setUserMoney(new BigDecimal(tradeUser.getUserMoney()).add(userMoneyLog.getUseMoney()).longValue());userMapper.updateByPrimaryKey(tradeUser);}//5.记录订单余额使用日志userMoneyLog.setCreateTime(new Date());userMoneyLogMapper.insert(userMoneyLog);return new Result(ShopCode.SHOP_SUCCESS.getSuccess(),ShopCode.SHOP_SUCCESS.getMessage());}
}
8.6、创建 类 UserServiceApplication.java
package com.itheima.shop;import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@EnableDubboConfiguration
public class UserServiceApplication {public static void main(String[] args) {SpringApplication.run(UserServiceApplication.class,args);}}
8.7、创建 文件 TradeUserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.itheima.shop.mapper.TradeUserMapper" ><resultMap id="BaseResultMap" type="com.itheima.shop.pojo.TradeUser" ><id column="user_id" property="userId" jdbcType="BIGINT" /><result column="user_name" property="userName" jdbcType="VARCHAR" /><result column="user_password" property="userPassword" jdbcType="VARCHAR" /><result column="user_mobile" property="userMobile" jdbcType="VARCHAR" /><result column="user_score" property="userScore" jdbcType="INTEGER" /><result column="user_reg_time" property="userRegTime" jdbcType="TIMESTAMP" /><result column="user_money" property="userMoney" jdbcType="DECIMAL" /></resultMap><sql id="Example_Where_Clause" ><where ><foreach collection="oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Update_By_Example_Where_Clause" ><where ><foreach collection="example.oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Base_Column_List" >user_id, user_name, user_password, user_mobile, user_score, user_reg_time, user_money</sql><select id="selectByExample" resultMap="BaseResultMap" parameterType="com.itheima.shop.pojo.TradeUserExample" >select<if test="distinct" >distinct</if><include refid="Base_Column_List" />from trade_user<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if><if test="orderByClause != null" >order by ${orderByClause}</if></select><select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >select <include refid="Base_Column_List" />from trade_userwhere user_id = #{userId,jdbcType=BIGINT}</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Long" >delete from trade_userwhere user_id = #{userId,jdbcType=BIGINT}</delete><delete id="deleteByExample" parameterType="com.itheima.shop.pojo.TradeUserExample" >delete from trade_user<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></delete><insert id="insert" parameterType="com.itheima.shop.pojo.TradeUser" >insert into trade_user (user_id, user_name, user_password, user_mobile, user_score, user_reg_time, user_money)values (#{userId,jdbcType=BIGINT}, #{userName,jdbcType=VARCHAR}, #{userPassword,jdbcType=VARCHAR}, #{userMobile,jdbcType=VARCHAR}, #{userScore,jdbcType=INTEGER}, #{userRegTime,jdbcType=TIMESTAMP}, #{userMoney,jdbcType=DECIMAL})</insert><insert id="insertSelective" parameterType="com.itheima.shop.pojo.TradeUser" >insert into trade_user<trim prefix="(" suffix=")" suffixOverrides="," ><if test="userId != null" >user_id,</if><if test="userName != null" >user_name,</if><if test="userPassword != null" >user_password,</if><if test="userMobile != null" >user_mobile,</if><if test="userScore != null" >user_score,</if><if test="userRegTime != null" >user_reg_time,</if><if test="userMoney != null" >user_money,</if></trim><trim prefix="values (" suffix=")" suffixOverrides="," ><if test="userId != null" >#{userId,jdbcType=BIGINT},</if><if test="userName != null" >#{userName,jdbcType=VARCHAR},</if><if test="userPassword != null" >#{userPassword,jdbcType=VARCHAR},</if><if test="userMobile != null" >#{userMobile,jdbcType=VARCHAR},</if><if test="userScore != null" >#{userScore,jdbcType=INTEGER},</if><if test="userRegTime != null" >#{userRegTime,jdbcType=TIMESTAMP},</if><if test="userMoney != null" >#{userMoney,jdbcType=DECIMAL},</if></trim></insert><select id="countByExample" parameterType="com.itheima.shop.pojo.TradeUserExample" resultType="java.lang.Integer" >select count(*) from trade_user<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></select><update id="updateByExampleSelective" parameterType="map" >update trade_user<set ><if test="record.userId != null" >user_id = #{record.userId,jdbcType=BIGINT},</if><if test="record.userName != null" >user_name = #{record.userName,jdbcType=VARCHAR},</if><if test="record.userPassword != null" >user_password = #{record.userPassword,jdbcType=VARCHAR},</if><if test="record.userMobile != null" >user_mobile = #{record.userMobile,jdbcType=VARCHAR},</if><if test="record.userScore != null" >user_score = #{record.userScore,jdbcType=INTEGER},</if><if test="record.userRegTime != null" >user_reg_time = #{record.userRegTime,jdbcType=TIMESTAMP},</if><if test="record.userMoney != null" >user_money = #{record.userMoney,jdbcType=DECIMAL},</if></set><if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByExample" parameterType="map" >update trade_userset user_id = #{record.userId,jdbcType=BIGINT},user_name = #{record.userName,jdbcType=VARCHAR},user_password = #{record.userPassword,jdbcType=VARCHAR},user_mobile = #{record.userMobile,jdbcType=VARCHAR},user_score = #{record.userScore,jdbcType=INTEGER},user_reg_time = #{record.userRegTime,jdbcType=TIMESTAMP},user_money = #{record.userMoney,jdbcType=DECIMAL}<if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByPrimaryKeySelective" parameterType="com.itheima.shop.pojo.TradeUser" >update trade_user<set ><if test="userName != null" >user_name = #{userName,jdbcType=VARCHAR},</if><if test="userPassword != null" >user_password = #{userPassword,jdbcType=VARCHAR},</if><if test="userMobile != null" >user_mobile = #{userMobile,jdbcType=VARCHAR},</if><if test="userScore != null" >user_score = #{userScore,jdbcType=INTEGER},</if><if test="userRegTime != null" >user_reg_time = #{userRegTime,jdbcType=TIMESTAMP},</if><if test="userMoney != null" >user_money = #{userMoney,jdbcType=DECIMAL},</if></set>where user_id = #{userId,jdbcType=BIGINT}</update><update id="updateByPrimaryKey" parameterType="com.itheima.shop.pojo.TradeUser" >update trade_userset user_name = #{userName,jdbcType=VARCHAR},user_password = #{userPassword,jdbcType=VARCHAR},user_mobile = #{userMobile,jdbcType=VARCHAR},user_score = #{userScore,jdbcType=INTEGER},user_reg_time = #{userRegTime,jdbcType=TIMESTAMP},user_money = #{userMoney,jdbcType=DECIMAL}where user_id = #{userId,jdbcType=BIGINT}</update>
</mapper>
8.8、创建 文件 TradeUserMoneyLogMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.itheima.shop.mapper.TradeUserMoneyLogMapper" ><resultMap id="BaseResultMap" type="com.itheima.shop.pojo.TradeUserMoneyLog" ><id column="user_id" property="userId" jdbcType="BIGINT" /><id column="order_id" property="orderId" jdbcType="BIGINT" /><id column="money_log_type" property="moneyLogType" jdbcType="INTEGER" /><result column="use_money" property="useMoney" jdbcType="DECIMAL" /><result column="create_time" property="createTime" jdbcType="TIMESTAMP" /></resultMap><sql id="Example_Where_Clause" ><where ><foreach collection="oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Update_By_Example_Where_Clause" ><where ><foreach collection="example.oredCriteria" item="criteria" separator="or" ><if test="criteria.valid" ><trim prefix="(" suffix=")" prefixOverrides="and" ><foreach collection="criteria.criteria" item="criterion" ><choose ><when test="criterion.noValue" >and ${criterion.condition}</when><when test="criterion.singleValue" >and ${criterion.condition} #{criterion.value}</when><when test="criterion.betweenValue" >and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}</when><when test="criterion.listValue" >and ${criterion.condition}<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >#{listItem}</foreach></when></choose></foreach></trim></if></foreach></where></sql><sql id="Base_Column_List" >user_id, order_id, money_log_type, use_money, create_time</sql><select id="selectByExample" resultMap="BaseResultMap" parameterType="com.itheima.shop.pojo.TradeUserMoneyLogExample" >select<if test="distinct" >distinct</if><include refid="Base_Column_List" />from trade_user_money_log<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if><if test="orderByClause != null" >order by ${orderByClause}</if></select><select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="com.itheima.shop.pojo.TradeUserMoneyLogKey" >select <include refid="Base_Column_List" />from trade_user_money_logwhere user_id = #{userId,jdbcType=BIGINT}and order_id = #{orderId,jdbcType=BIGINT}and money_log_type = #{moneyLogType,jdbcType=INTEGER}</select><delete id="deleteByPrimaryKey" parameterType="com.itheima.shop.pojo.TradeUserMoneyLogKey" >delete from trade_user_money_logwhere user_id = #{userId,jdbcType=BIGINT}and order_id = #{orderId,jdbcType=BIGINT}and money_log_type = #{moneyLogType,jdbcType=INTEGER}</delete><delete id="deleteByExample" parameterType="com.itheima.shop.pojo.TradeUserMoneyLogExample" >delete from trade_user_money_log<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></delete><insert id="insert" parameterType="com.itheima.shop.pojo.TradeUserMoneyLog" >insert into trade_user_money_log (user_id, order_id, money_log_type, use_money, create_time)values (#{userId,jdbcType=BIGINT}, #{orderId,jdbcType=BIGINT}, #{moneyLogType,jdbcType=INTEGER}, #{useMoney,jdbcType=DECIMAL}, #{createTime,jdbcType=TIMESTAMP})</insert><insert id="insertSelective" parameterType="com.itheima.shop.pojo.TradeUserMoneyLog" >insert into trade_user_money_log<trim prefix="(" suffix=")" suffixOverrides="," ><if test="userId != null" >user_id,</if><if test="orderId != null" >order_id,</if><if test="moneyLogType != null" >money_log_type,</if><if test="useMoney != null" >use_money,</if><if test="createTime != null" >create_time,</if></trim><trim prefix="values (" suffix=")" suffixOverrides="," ><if test="userId != null" >#{userId,jdbcType=BIGINT},</if><if test="orderId != null" >#{orderId,jdbcType=BIGINT},</if><if test="moneyLogType != null" >#{moneyLogType,jdbcType=INTEGER},</if><if test="useMoney != null" >#{useMoney,jdbcType=DECIMAL},</if><if test="createTime != null" >#{createTime,jdbcType=TIMESTAMP},</if></trim></insert><select id="countByExample" parameterType="com.itheima.shop.pojo.TradeUserMoneyLogExample" resultType="java.lang.Integer" >select count(*) from trade_user_money_log<if test="_parameter != null" ><include refid="Example_Where_Clause" /></if></select><update id="updateByExampleSelective" parameterType="map" >update trade_user_money_log<set ><if test="record.userId != null" >user_id = #{record.userId,jdbcType=BIGINT},</if><if test="record.orderId != null" >order_id = #{record.orderId,jdbcType=BIGINT},</if><if test="record.moneyLogType != null" >money_log_type = #{record.moneyLogType,jdbcType=INTEGER},</if><if test="record.useMoney != null" >use_money = #{record.useMoney,jdbcType=DECIMAL},</if><if test="record.createTime != null" >create_time = #{record.createTime,jdbcType=TIMESTAMP},</if></set><if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByExample" parameterType="map" >update trade_user_money_logset user_id = #{record.userId,jdbcType=BIGINT},order_id = #{record.orderId,jdbcType=BIGINT},money_log_type = #{record.moneyLogType,jdbcType=INTEGER},use_money = #{record.useMoney,jdbcType=DECIMAL},create_time = #{record.createTime,jdbcType=TIMESTAMP}<if test="_parameter != null" ><include refid="Update_By_Example_Where_Clause" /></if></update><update id="updateByPrimaryKeySelective" parameterType="com.itheima.shop.pojo.TradeUserMoneyLog" >update trade_user_money_log<set ><if test="useMoney != null" >use_money = #{useMoney,jdbcType=DECIMAL},</if><if test="createTime != null" >create_time = #{createTime,jdbcType=TIMESTAMP},</if></set>where user_id = #{userId,jdbcType=BIGINT}and order_id = #{orderId,jdbcType=BIGINT}and money_log_type = #{moneyLogType,jdbcType=INTEGER}</update><update id="updateByPrimaryKey" parameterType="com.itheima.shop.pojo.TradeUserMoneyLog" >update trade_user_money_logset use_money = #{useMoney,jdbcType=DECIMAL},create_time = #{createTime,jdbcType=TIMESTAMP}where user_id = #{userId,jdbcType=BIGINT}and order_id = #{orderId,jdbcType=BIGINT}and money_log_type = #{moneyLogType,jdbcType=INTEGER}</update>
</mapper>
8.9、创建 文件 application.properties
spring.application.name=dubbo-user-provider
spring.dubbo.application.id=dubbo-user-provider
spring.dubbo.application.name=dubbo-user-provider
spring.dubbo.registry.address=zookeeper://192.168.25.140:2181;zookeeper://192.168.25.140:2182;zookeeper://192.168.25.140:2183
spring.dubbo.server=true
spring.dubbo.protocol.name=dubbo
spring.dubbo.protocol.port=20883# DB
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/trade?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root#spring集成Mybatis环境
#pojo别名扫描包
mybatis.type-aliases-package=com.itheima.shop.pojo
#加载Mybatis映射文件
mybatis.mapper-locations=classpath:com/itheima/shop/mapper/*Mapper.xml# RocketMQ
rocketmq.name-server=192.168.25.135:9876;192.168.25.138:9876
rocketmq.producer.group=orderProducerGroupmq.order.consumer.group.name=order_orderTopic_cancel_group
mq.order.topic=orderTopic

9、创建 shop-order-web 订单系统 工程。

9.1、在 pom.xml 中,导入依赖坐标。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>shop-parent</artifactId><groupId>com.iteima.shop</groupId><version>1.0-SNAPSHOT</version><relativePath>../shop-parent/pom.xml</relativePath></parent><modelVersion>4.0.0</modelVersion><artifactId>shop-order-web</artifactId><dependencies><!--spring-webmvc--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--API--><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-api</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-common</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
<!-- D:\java-test\idea2019\shop\shop-order-web\pom.xml -->
9.2、创建 类 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);}}
9.3、创建 类 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 {@Referenceprivate IOrderService orderService;@RequestMapping("/confirm")public Result confirmOrder(@RequestBody TradeOrder order){return orderService.confirmOrder(order);}}
9.4、创建 类 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();// msfactory.setReadTimeout(15000);// msfactory.setConnectTimeout(15000);return factory;}}
9.5、创建 配置文件 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:2183order.port=8080
shop.order.baseURI=${server.host}:${order.port}${server.servlet.path}
shop.order.confirm=/order/confirm
9.6、创建 测试 类 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 {@Autowiredprivate RestTemplate restTemplate;@Value("${shop.order.baseURI}")private String baseURI;@Value("${shop.order.confirm}")private String confirmOrderPath;@Testpublic 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);}}

10、创建 shop-pay-web 支付系统 工程。

10.1、在 pom.xml 中,导入依赖坐标。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>shop-parent</artifactId><groupId>com.iteima.shop</groupId><version>1.0-SNAPSHOT</version><relativePath>../shop-parent/pom.xml</relativePath></parent><modelVersion>4.0.0</modelVersion><artifactId>shop-pay-web</artifactId><dependencies><!--spring-webmvc--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--API--><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-api</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.iteima.shop</groupId><artifactId>shop-common</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
<!-- D:\java-test\idea2019\shop\shop-pay-web\pom.xml -->
10.2、创建 类 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);}}
10.3、创建 类 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 {@Referenceprivate 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);}}
10.4、创建 类 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();// msfactory.setReadTimeout(15000);// msfactory.setConnectTimeout(15000);return factory;}}
10.5、创建 配置文件 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:2183pay.port=9090shop.pay.baseURI=${server.host}:${pay.port}${server.servlet.path}shop.pay.createPayment=/pay/createPaymentshop.pay.callbackPayment=/pay/callBackPayment
10.6、创建 测试 类 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 {@Autowiredprivate RestTemplate restTemplate;@Value("${shop.pay.baseURI}")private String baseURI;@Value("${shop.pay.createPayment}")private String createPaymentPath;@Value("${shop.pay.callbackPayment}")private String callBackPaymentPath;@Testpublic void createPayment(){long orderId = 352537369385242624L;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);}@Testpublic 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);}}

11、创建 shop-pojo 实体类 工程。

11.1、在 pom.xml 中,导入依赖坐标。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>shop-parent</artifactId><groupId>com.iteima.shop</groupId><version>1.0-SNAPSHOT</version><relativePath>../shop-parent/pom.xml</relativePath></parent><modelVersion>4.0.0</modelVersion><artifactId>shop-pojo</artifactId></project>
<!-- D:\java-test\idea2019\shop\shop-pojo\pom.xml -->

上一节关联链接请点击:
# RocketMQ 实战:模拟电商网站场景综合案例(二)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/25905.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Web 自动化测试(基于Pytest极简)

Pytest 初体验 在使用 Python 进行 Web UI 自动化测试时&#xff0c;我们除了使用 unittest 单元测试框架&#xff0c;还可以使用 pytest&#xff0c;本节实验就给大家简单的介绍一下 pytest。 环境配置 本系列实验我们借助 VS Code 工具编写代码&#xff0c;使用的 Python …

IP地址简介

一、IP地址 Internet Protocol Address&#xff0c;即网络层协议地址&#xff0c;是IP的缩写。 二、IP地址的作用 为什么不直接使用MAC&#xff0c;又加了一个IP地址呢&#xff1f; 事实上底层传输&#xff0c;最终使用的肯定是MAC地址&#xff0c;但是由于在以前&#x…

Elasticsearch-经纬度查询(8.x)

目录 一、开发环境 二、pom文件 三、ES配置文件 四、ES相关字段 五、ES半径查询 ES的字段类型:geo_point&#xff0c;可以实现以一个点为中心的半径查询(geo_distance query) ES 地里位置查询: 半径查询(geo_distance query)查询指定矩形内的数据(geo_bounding_box quer…

管理数据必备;侦听器watch用法详解,vue2与vue3中watch的变化与差异

目录 一、侦听器&#xff08;watch&#xff09;是什么&#xff1f; 二、Vue2中的watch&#xff08;Options API&#xff09; 2.1、函数式写法 2.2、对象式写法 ①对象式基础写法 ②回调函数handler ③deep属性 ④immediate属性 三、Vue3中的watch 3.1、向下兼容&#xff…

部署higress到华为云

higress 部署与上云 k3s环境准备 [root@vm ~]# curl https://releases.rancher.com/install-docker/19.03.sh | sh [root@vm ~]# curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"[root@vm ~]# …

C++面向对象程序设计 - 输入输出流进一步研究

在C中&#xff0c;输入输出流&#xff08;I/O&#xff09;是一个强大的特性&#xff0c;它允许程序与各种输入/输出设备&#xff08;如键盘、显示器、文件等&#xff09;进行交互。C标准库中的<iostream>头文件定义了基本的输入输出流类&#xff0c;如std::cin&#xff0…

搭建RocketMQ主从异步集群

搭建RocketMQ主从异步集群 1、RocketMQ集群模式 为了追求更好的性能&#xff0c;RocketMQ的最佳实践方式都是在集群模式下完成的。RocketMQ官方提供了三种集群搭建方式&#xff1a; 2主2从异步通信方式&#xff1a;使用异步方式进行主从之间的数据复制。吞吐量大&#xff0c;…

665. 非递减数列(中等)

665. 非递减数列 1. 题目描述2.详细题解3.代码实现3.1 Python3.2 Java 1. 题目描述 题目中转&#xff1a;665. 非递减数列 2.详细题解 判断在最多改变 1 个元素的情况下&#xff0c;该数组能否变成一个非递减数列&#xff0c;一看到题目&#xff0c;不就是遍历判断有几处不…

科普计算机的相关知识【上】

一、计算机硬件 1. 主板&#xff08;Motherboard&#xff09; 定义&#xff1a;主板是计算机系统的核心&#xff0c;承载着CPU、内存和扩展卡等关键组件。 功能&#xff1a;主板负责连接和协调各个硬件组件&#xff0c;确保它们能够正常工作。 主要芯片&#xff1a;包括BIO…

Android之保存图片到相册之前兼容不同机型需要注意的配置

一、存储配置相关说明 1、权限配置 <uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name"…

现实转虚拟:Video2Game引领3D互动体验

在当今数字化时代&#xff0c;虚拟环境的创建对于游戏开发、虚拟现实应用和自动驾驶模拟器等多个领域至关重要。然而&#xff0c;传统的虚拟环境创建过程不仅复杂而且成本高昂&#xff0c;通常需要专业人员和专业软件开发工具的参与。例如&#xff0c;著名的《侠盗猎车手V》以其…

升级海光dcu的飞桨版本@启智

dcu的调试任务启动之后&#xff0c;上不了网啊&#xff0c;导致无法升级python到3.10,进而无法升级飞桨版本.... sudo python -m pip install --pre paddlepaddle-dcu -i https://www.paddlepaddle.org.cn/packages/nightly/dcu/ Looking in indexes: https://www.paddlepaddle…

GUI编程02-布局管理器

流式布局 FlowLayout 东西南北中 BorderLayout 表格布局 GridLayout 流式布局 package YMP.GUI; ​ import java.awt.*; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; ​ public class TestFlowLayout {public static void main(String[] args…

QSlider样式示例

参考代码&#xff1a; /********************QSlider横向滑动条样式**********************/ QSlider {background-color: rgba(170, 255, 255, 100); /* 设置滑动条主体*/ }QSlider::groove:horizontal {border: 1px solid #999999;height: 8px; /* 默认…

猫头虎分享已解决Bug || Uncaught TypeError: Cannot set property ‘innerHTML‘ of null**

猫头虎分享已解决Bug || Uncaught TypeError: Cannot set property ‘innerHTML’ of null** 原创作者&#xff1a; 猫头虎 作者微信号&#xff1a; Libin9iOak 作者公众号&#xff1a; 猫头虎技术团队 更新日期&#xff1a; 2024年6月6日 博主猫头虎的技术世界 &#x…

【InternLM实战营第二期笔记】07:OpenCompass :是骡子是马,拉出来溜溜

文章目录 课程实操 课程 评测的意义是什么呢&#xff1f;我最近也在想。看到这节开头的内容后忽然有个顿悟&#xff1a;如果大模型最终也会变成一种基础工具&#xff08;类比软件&#xff09;&#xff0c;稳定或可预期的效果需要先于用户感知构建出来&#xff0c;评测 case 就…

创新案例|创新实时零售模式,千亿时尚巨头Shein的全球扩张之路

SHEIN&#xff0c;一家估值千亿美元的快时尚电商独角兽&#xff0c;是全球增长最快的服饰平台。它通过数据和平台的双轮驱动&#xff0c;构建了全新的“实时零售”模式&#xff0c;实现了数据与商业的紧密衔接。同时&#xff0c;通过领导力和组织能力建设&#xff0c;打造了独特…

两句话让LLM逻辑推理瞬间崩溃!!

一道简单的逻辑问题&#xff0c;竟让几乎所有的LLM全军覆没&#xff1f; 对于人类来说&#xff0c;这个名为「爱丽丝梦游仙境」&#xff08;AIW&#xff09;的测试并不算很难—— 「爱丽丝有N个兄弟&#xff0c;她还有M个姐妹。爱丽丝的兄弟有多少个姐妹&#xff1f;」 稍加思考…

spring和Mybatis的动态sql

文章目录 九、动态sql9.1、if9.2、where9.3 trim9.4、choose、when、otherwise9.5、foreach9.6、sql片段 九、动态sql MyBatis框架的动态sql技术&#xff0c;是一种根据特定条件动态拼装sql语句的功能&#xff0c;它存在的意义是为了解决拼接sql语句字符串的痛点问题 9.1、if …

LabVIEW开发实验室超导体电流特性测试系统

本系统旨在为学校实验室提供一个基于LabVIEW的超导体电流特性测试平台&#xff0c;通过精确测量超导体在不同温度和电流条件下的电学特性&#xff0c;帮助学生和研究人员深入理解超导体的物理性质。本文将从背景、目标、工作原理、使用方法、操作流程和注意事项等方面详细介绍该…