RocketMQ 实战:模拟电商网站场景综合案例(三)
一、环境搭建:数据库表结构介绍
1、优惠券表
Field Type Comment coupon_id decigint(50) NOT NULL 优惠券ID coupon_price decimal(10,2) NULL 优惠券金额 user id bigint(50) NULL 用户ID order id bigint(32)NULL 订单ID is used int(1) NULL 是否使用 0未使用 1已使用 used time timestamp NULL 使用时间
2、商品表
Field Type Comment goods id bigint(50) NOT NULL 主键 goods name varchar(255) NULL 商品名称 goods number int(11) NULL 商品库存 goods_price decimal(10,2) NULL 商品价格 goods desc varchar(255) NULL 商品描述 add time timestamp NULL 添加时间
3、订单表
Field Type Comment order _id bigint(50) NOT NULL 订单ID user _id bigint(50) NULL 用户ID order status int(1) NULL 订单状态 0未确认 1己确认 2已取消 3无效 4退款 pay_status int(1) NULL 支付状态 0未支付 1支付中 2已支付 shipping_status int(1) NULL 发货状态 0未发货 1已发货 2已退货 address varchar(255) NULL 收货地址 consignee varchar(255)NULL 收货人 goods id bigint(50) NULL 商品ID goods number int(11) NULL 商品数量 goods price decimal(10,2) NULL 商品价格 goods amount decimal(10,0) NULL 商品总价 shipping_fee decimal(10,2) NULL 运费 order amount decimal(10,2) NULL 订单价格 coupon_id bigint(50) NULL 优惠券ID coupon_paid decimal(10,2) NULL 优惠券 money_paid decimal(10,2) NULL 已付金额 pay_amount decimal(10,2) NULL 支付金额 add time timestamp NULL 创建时间
4、订单商品日志表
Field Type Comment goods id int(11) NOT NULL 商品ID order id varchar(32) NOT NULL 订单ID goods number int(11) NULL 库存数量 log_time datetime NULL 记录时间
5、用户表
Field Type Comment user id bigint(50) NOT NULL 用户ID user_name varchar(255) NULL 用户姓名 user password varchar(255)NULL 用户密码 user mobile varchar(255)NULL 手机号 user score int(11)NULL 积分 user_reg_time timestamp NULL 注册时间 user money decimal(10,0)NULL 用户余额
6、用户余额日志表
Field Type Comment Juser id bigint(50) NOT NULL 用户ID order id bigint(50) NOT NULL 订单ID money_log_type int(1) NOT NULL 日志类型 1订单付款 2 订单退款 use money decimal(10,2) NULL 操作金额 create time timestamp NULL 日志时间
7、订单支付表
Field Type Comment pay_id bigint(50) NOT NULL 支付编号 order id bigint(50) NULL 订单编号 pay_amount decimal(10,2) NULL 支付金额 is_paid int(1) NULL 是否已支付 1否 2是
8、MQ 消息生产表
Field Type Comment id varchar(100) NOT NULL 主键 group _name varchar(100) NULL 生产者组名 msg_topic varchar(100) NULL 消息主题 msg_tag varchar(100) NULL Tag msg_key varchar(100) NULL Key hsg body varchar(500) NULL 消息内容 msg status int(1)NULL 0:未处理;1:已经处理 create time timestamp NOT NULL 记录时间
9、MQ 消息消费表
Field Type Comment msg_id varchar(50) NULL 消息ID group name varchar(100) NOT NULL 消费者组名 msg_tag varchar(100) NOT NULL Tag msg_key varchar(100) NOT NULL Key msg_body varchar(500) NULL 消息体 consumer status int(1) NULL 0:正在处理;1:处理成功;2:处理失败 consumer times int(1)NULL 消费次数 consumer_timestamp timestamp NULL 消费时间 remark varchar(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 , "优惠券使用失败" ) ,
//余额不能小于0
SHOP_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;
}
@Override
public 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 {
//不同毫秒内,序列号置为0
sequence = 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> {
@Autowired
private TradeCouponMapper couponMapper;
@Override
public 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{
@Autowired
private TradeCouponMapper couponMapper;
@Override
public TradeCoupon findOne( Long coupouId) {
if( coupouId== null) {
CastException.cast( ShopCode.SHOP_REQUEST_PARAMETER_VALID) ;
}
return couponMapper.selectByPrimaryKey( coupouId) ;
}
@Override
public 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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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_coupon
where coupon_id =
< /select>
< delete id = "deleteByPrimaryKey" parameterType = "java.lang.Long" >
delete from trade_coupon
where coupon_id =
< /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 (
)
< /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" >
< /if>
< if test = "couponPrice != null" >
< /if>
< if test = "userId != null" >
< /if>
< if test = "orderId != null" >
< /if>
< if test = "isUsed != null" >
< /if>
< if test = "usedTime != null" >
< /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 =
< /if>
< if test = "record.couponPrice != null" >
coupon_price =
< /if>
< if test = "record.userId != null" >
user_id =
< /if>
< if test = "record.orderId != null" >
order_id =
< /if>
< if test = "record.isUsed != null" >
is_used =
< /if>
< if test = "record.usedTime != null" >
used_time =
< /if>
< /set>
< if test = "_parameter != null" >
< include refid = "Update_By_Example_Where_Clause" />
< /if>
< /update>
< update id = "updateByExample" parameterType = "map" >
update trade_coupon
set coupon_id =
coupon_price =
user_id =
order_id =
is_used =
used_time =
< 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 =
< /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>
< /set>
where coupon_id =
< /update>
< update id = "updateByPrimaryKey" parameterType = "com.itheima.shop.pojo.TradeCoupon" >
update trade_coupon
set coupon_price =
user_id =
order_id =
is_used =
used_time =
where coupon_id =
< /update>
< /mapper>
4.7 创建 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
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.type-aliases-package= com.itheima.shop.pojo
mybatis.mapper-locations= classpath:com/itheima/shop/mapper/*Mapper.xml
rocketmq.name-server= 192.168 .25.135:9876; 192.168 .25.138:9876
rocketmq.producer.group = orderProducerGroup
mq.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;
@Autowired
private TradeGoodsMapper goodsMapper;
@Autowired
private TradeMqConsumerLogMapper mqConsumerLogMapper;
@Autowired
private TradeGoodsNumberLogMapper goodsNumberLogMapper;
@Override
public 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 {
@Autowired
private TradeGoodsMapper goodsMapper;
@Autowired
private TradeGoodsNumberLogMapper goodsNumberLogMapper;
@Override
public TradeGoods findOne( Long goodsId) {
if ( goodsId == null) {
CastException.cast( ShopCode.SHOP_REQUEST_PARAMETER_VALID) ;
}
return goodsMapper.selectByPrimaryKey( goodsId) ;
}
@Override
public 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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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_goods
where goods_id =
< /select>
< delete id = "deleteByPrimaryKey" parameterType = "java.lang.Long" >
delete from trade_goods
where goods_id =
< /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 (
)
< /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" >
< /if>
< if test = "goodsName != null" >
< /if>
< if test = "goodsNumber != null" >
< /if>
< if test = "goodsPrice != null" >
< /if>
< if test = "goodsDesc != null" >
< /if>
< if test = "addTime != null" >
< /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 =
< /if>
< if test = "record.goodsName != null" >
goods_name =
< /if>
< if test = "record.goodsNumber != null" >
goods_number =
< /if>
< if test = "record.goodsPrice != null" >
goods_price =
< /if>
< if test = "record.goodsDesc != null" >
goods_desc =
< /if>
< if test = "record.addTime != null" >
add_time =
< /if>
< /set>
< if test = "_parameter != null" >
< include refid = "Update_By_Example_Where_Clause" />
< /if>
< /update>
< update id = "updateByExample" parameterType = "map" >
update trade_goods
set goods_id =
goods_name =
goods_number =
goods_price =
goods_desc =
add_time =
< 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 =
< /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>
< /set>
where goods_id =
< /update>
< update id = "updateByPrimaryKey" parameterType = "com.itheima.shop.pojo.TradeGoods" >
update trade_goods
set goods_name =
goods_number =
goods_price =
goods_desc =
add_time =
where goods_id =
< /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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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_log
where goods_id =
and order_id =
< /select>
< delete id = "deleteByPrimaryKey" parameterType = "com.itheima.shop.pojo.TradeGoodsNumberLogKey" >
delete from trade_goods_number_log
where goods_id =
and order_id =
< /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 (
< /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" >
< /if>
< if test = "orderId != null" >
< /if>
< if test = "goodsNumber != null" >
< /if>
< if test = "logTime != null" >
< /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 =
< /if>
< if test = "record.orderId != null" >
order_id =
< /if>
< if test = "record.goodsNumber != null" >
goods_number =
< /if>
< if test = "record.logTime != null" >
log_time =
< /if>
< /set>
< if test = "_parameter != null" >
< include refid = "Update_By_Example_Where_Clause" />
< /if>
< /update>
< update id = "updateByExample" parameterType = "map" >
update trade_goods_number_log
set goods_id =
order_id =
goods_number =
log_time =
< 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 =
< /if>
< if test = "logTime != null" >
log_time =
< /if>
< /set>
where goods_id =
and order_id =
< /update>
< update id = "updateByPrimaryKey" parameterType = "com.itheima.shop.pojo.TradeGoodsNumberLog" >
update trade_goods_number_log
set goods_number =
log_time =
where goods_id =
and order_id =
< /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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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_log
where group_name =
and msg_tag =
and msg_key =
< /select>
< delete id = "deleteByPrimaryKey" parameterType = "com.itheima.shop.pojo.TradeMqConsumerLogKey" >
delete from trade_mq_consumer_log
where group_name =
and msg_tag =
and msg_key =
< /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 (
)
< /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" >
< /if>
< if test = "msgTag != null" >
< /if>
< if test = "msgKey != null" >
< /if>
< if test = "msgId != null" >
< /if>
< if test = "msgBody != null" >
< /if>
< if test = "consumerStatus != null" >
< /if>
< if test = "consumerTimes != null" >
< /if>
< if test = "consumerTimestamp != null" >
< /if>
< if test = "remark != null" >
< /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 =
< /if>
< if test = "record.msgTag != null" >
msg_tag =
< /if>
< if test = "record.msgKey != null" >
msg_key =
< /if>
< if test = "record.msgId != null" >
msg_id =
< /if>
< if test = "record.msgBody != null" >
msg_body =
< /if>
< if test = "record.consumerStatus != null" >
consumer_status =
< /if>
< if test = "record.consumerTimes != null" >
consumer_times =
< /if>
< if test = "record.consumerTimestamp != null" >
consumer_timestamp =
< /if>
< if test = "record.remark != null" >
remark =
< /if>
< /set>
< if test = "_parameter != null" >
< include refid = "Update_By_Example_Where_Clause" />
< /if>
< /update>
< update id = "updateByExample" parameterType = "map" >
update trade_mq_consumer_log
set group_name =
msg_tag =
msg_key =
msg_id =
msg_body =
consumer_status =
consumer_times =
consumer_timestamp =
remark =
< 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 =
< /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>
< /set>
where group_name =
and msg_tag =
and msg_key =
< /update>
< update id = "updateByPrimaryKey" parameterType = "com.itheima.shop.pojo.TradeMqConsumerLog" >
update trade_mq_consumer_log
set msg_id =
msg_body =
consumer_status =
consumer_times =
consumer_timestamp =
remark =
where group_name =
and msg_tag =
and msg_key =
< /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
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.type-aliases-package= com.itheima.shop.pojo
mybatis.mapper-locations= classpath:com/itheima/shop/mapper/*Mapper.xml
rocketmq.name-server= 192.168 .25.135:9876; 192.168 .25.138:9876
rocketmq.producer.group = orderProducerGroup
mq.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> {
@Autowired
private TradeOrderMapper orderMapper;
@Override
public 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> {
@Autowired
private TradeOrderMapper orderMapper;
@Override
public 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 {
@Reference
private IGoodsService goodsService;
@Reference
private IUserService userService;
@Reference
private ICouponService couponService;
@Value( "${mq.order.topic} " )
private String topic;
@Value( "${mq.order.tag.cancel} " )
private String tag;
@Autowired
private TradeOrderMapper orderMapper;
@Autowired
private IDWorker idWorker;
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Override
public 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. 设置订单ID
long 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) ;
//余额小于0
if( r== -1) {
CastException.cast( ShopCode.SHOP_MONEY_PAID_LESS_ZERO) ;
}
//余额大于0
if( 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.返回订单ID
return 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) ;
}
@Bean
public 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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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_order
where order_id =
< /select>
< delete id = "deleteByPrimaryKey" parameterType = "java.lang.Long" >
delete from trade_order
where order_id =
< /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 (
< /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" >
< /if>
< if test = "userId != null" >
< /if>
< if test = "orderStatus != null" >
< /if>
< if test = "payStatus != null" >
< /if>
< if test = "shippingStatus != null" >
< /if>
< if test = "address != null" >
< /if>
< if test = "consignee != null" >
< /if>
< if test = "goodsId != null" >
< /if>
< if test = "goodsNumber != null" >
< /if>
< if test = "goodsPrice != null" >
< /if>
< if test = "goodsAmount != null" >
< /if>
< if test = "shippingFee != null" >
< /if>
< if test = "orderAmount != null" >
< /if>
< if test = "couponId != null" >
< /if>
< if test = "couponPaid != null" >
< /if>
< if test = "moneyPaid != null" >
< /if>
< if test = "payAmount != null" >
< /if>
< if test = "addTime != null" >
< /if>
< if test = "confirmTime != null" >
< /if>
< if test = "payTime != null" >
< /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 =
< /if>
< if test = "record.userId != null" >
user_id =
< /if>
< if test = "record.orderStatus != null" >
order_status =
< /if>
< if test = "record.payStatus != null" >
pay_status =
< /if>
< if test = "record.shippingStatus != null" >
shipping_status =
< /if>
< if test = "record.address != null" >
address =
< /if>
< if test = "record.consignee != null" >
consignee =
< /if>
< if test = "record.goodsId != null" >
goods_id =
< /if>
< if test = "record.goodsNumber != null" >
goods_number =
< /if>
< if test = "record.goodsPrice != null" >
goods_price =
< /if>
< if test = "record.goodsAmount != null" >
goods_amount =
< /if>
< if test = "record.shippingFee != null" >
shipping_fee =
< /if>
< if test = "record.orderAmount != null" >
order_amount =
< /if>
< if test = "record.couponId != null" >
coupon_id =
< /if>
< if test = "record.couponPaid != null" >
coupon_paid =
< /if>
< if test = "record.moneyPaid != null" >
money_paid =
< /if>
< if test = "record.payAmount != null" >
pay_amount =
< /if>
< if test = "record.addTime != null" >
add_time =
< /if>
< if test = "record.confirmTime != null" >
confirm_time =
< /if>
< if test = "record.payTime != null" >
pay_time =
< /if>
< /set>
< if test = "_parameter != null" >
< include refid = "Update_By_Example_Where_Clause" />
< /if>
< /update>
< update id = "updateByExample" parameterType = "map" >
update trade_order
set 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 =
< 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 =
< /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>
< /set>
where order_id =
< /update>
< update id = "updateByPrimaryKey" parameterType = "com.itheima.shop.pojo.TradeOrder" >
update trade_order
set 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 =
where order_id =
< /update>
< /mapper>
6.8、创建 文件 application.properties
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
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.type-aliases-package= com.itheima.shop.pojo
mybatis.mapper-locations= classpath:com/itheima/shop/mapper/*Mapper.xml
rocketmq.name-server= 192.168 .25.135:9876; 192.168 .25.138:9876
rocketmq.producer.group = orderProducerGroup
mq.order.consumer.group.name = order_orderTopic_cancel_group
mq.order.topic = orderTopic
mq.order.tag.cancel = order_cancel
mq.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 {
@Autowired
private IOrderService orderService;
@Test
public 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{
@Autowired
private TradePayMapper tradePayMapper;
@Autowired
private TradeMqProducerTempMapper mqProducerTempMapper;
@Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Autowired
private IDWorker idWorker;
@Value( "${rocketmq.producer.group} " )
private String groupName;
@Value( "${mq.topic} " )
private String topic;
@Value( "${mq.pay.tag} " )
private String tag;
@Override
public 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( )) ;
}
@Override
public 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 ( ) {
@Override
public void run ( ) {
//5. 发送消息到MQ
SendResult 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) ;
}
@Bean
public IDWorker getBean ( ) {
return new IDWorker( 1,2 ) ;
}
@Bean
public 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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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_temp
where id =
< /select>
< delete id = "deleteByPrimaryKey" parameterType = "java.lang.String" >
delete from trade_mq_producer_temp
where id =
< /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 (
< /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" >
< /if>
< if test = "groupName != null" >
< /if>
< if test = "msgTopic != null" >
< /if>
< if test = "msgTag != null" >
< /if>
< if test = "msgKey != null" >
< /if>
< if test = "msgBody != null" >
< /if>
< if test = "msgStatus != null" >
< /if>
< if test = "createTime != null" >
< /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 =
< /if>
< if test = "record.groupName != null" >
group_name =
< /if>
< if test = "record.msgTopic != null" >
msg_topic =
< /if>
< if test = "record.msgTag != null" >
msg_tag =
< /if>
< if test = "record.msgKey != null" >
msg_key =
< /if>
< if test = "record.msgBody != null" >
msg_body =
< /if>
< if test = "record.msgStatus != null" >
msg_status =
< /if>
< if test = "record.createTime != null" >
create_time =
< /if>
< /set>
< if test = "_parameter != null" >
< include refid = "Update_By_Example_Where_Clause" />
< /if>
< /update>
< update id = "updateByExample" parameterType = "map" >
update trade_mq_producer_temp
set id =
group_name =
msg_topic =
msg_tag =
msg_key =
msg_body =
msg_status =
create_time =
< 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 =
< /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>
< /set>
where id =
< /update>
< update id = "updateByPrimaryKey" parameterType = "com.itheima.shop.pojo.TradeMqProducerTemp" >
update trade_mq_producer_temp
set group_name =
msg_topic =
msg_tag =
msg_key =
msg_body =
msg_status =
create_time =
where id =
< /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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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_pay
where pay_id =
< /select>
< delete id = "deleteByPrimaryKey" parameterType = "java.lang.Long" >
delete from trade_pay
where pay_id =
< /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 (
< /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" >
< /if>
< if test = "orderId != null" >
< /if>
< if test = "payAmount != null" >
< /if>
< if test = "isPaid != null" >
< /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 =
< /if>
< if test = "record.orderId != null" >
order_id =
< /if>
< if test = "record.payAmount != null" >
pay_amount =
< /if>
< if test = "record.isPaid != null" >
is_paid =
< /if>
< /set>
< if test = "_parameter != null" >
< include refid = "Update_By_Example_Where_Clause" />
< /if>
< /update>
< update id = "updateByExample" parameterType = "map" >
update trade_pay
set pay_id =
order_id =
pay_amount =
is_paid =
< 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 =
< /if>
< if test = "payAmount != null" >
pay_amount =
< /if>
< if test = "isPaid != null" >
is_paid =
< /if>
< /set>
where pay_id =
< /update>
< update id = "updateByPrimaryKey" parameterType = "com.itheima.shop.pojo.TradePay" >
update trade_pay
set order_id =
pay_amount =
is_paid =
where pay_id =
< /update>
< /mapper>
7.8、创建 文件 application.properties
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
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.type-aliases-package= com.itheima.shop.pojo
mybatis.mapper-locations= classpath:com/itheima/shop/mapper/*Mapper.xml
rocketmq.name-server= 192.168 .25.135:9876; 192.168 .25.138:9876
rocketmq.producer.group = payProducerGroup
mq.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 {
@Autowired
private IPayService payService;
@Test
public void createPayment ( ) {
long orderId = 351526299216515072L;
TradePay tradePay = new TradePay( ) ;
tradePay.setOrderId( orderId) ;
tradePay.setPayAmount( new BigDecimal( 880 )) ;
payService.createPayment( tradePay) ;
}
@Test
public 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> {
@Autowired
private IUserService userService;
@Override
public 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{
@Autowired
private TradeUserMapper userMapper;
@Autowired
private TradeUserMoneyLogMapper userMoneyLogMapper;
@Override
public TradeUser findOne( Long userId) {
if( userId== null) {
CastException.cast( ShopCode.SHOP_REQUEST_PARAMETER_VALID) ;
}
return userMapper.selectByPrimaryKey( userId) ;
}
@Override
public 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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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_user
where user_id =
< /select>
< delete id = "deleteByPrimaryKey" parameterType = "java.lang.Long" >
delete from trade_user
where user_id =
< /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 (
< /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" >
< /if>
< if test = "userName != null" >
< /if>
< if test = "userPassword != null" >
< /if>
< if test = "userMobile != null" >
< /if>
< if test = "userScore != null" >
< /if>
< if test = "userRegTime != null" >
< /if>
< if test = "userMoney != null" >
< /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 =
< /if>
< if test = "record.userName != null" >
user_name =
< /if>
< if test = "record.userPassword != null" >
user_password =
< /if>
< if test = "record.userMobile != null" >
user_mobile =
< /if>
< if test = "record.userScore != null" >
user_score =
< /if>
< if test = "record.userRegTime != null" >
user_reg_time =
< /if>
< if test = "record.userMoney != null" >
user_money =
< /if>
< /set>
< if test = "_parameter != null" >
< include refid = "Update_By_Example_Where_Clause" />
< /if>
< /update>
< update id = "updateByExample" parameterType = "map" >
update trade_user
set user_id =
user_name =
user_password =
user_mobile =
user_score =
user_reg_time =
user_money =
< 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 =
< /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>
< /set>
where user_id =
< /update>
< update id = "updateByPrimaryKey" parameterType = "com.itheima.shop.pojo.TradeUser" >
update trade_user
set user_name =
user_password =
user_mobile =
user_score =
user_reg_time =
user_money =
where user_id =
< /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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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}
< /when>
< when test = "criterion.betweenValue" >
and ${criterion.condition}
< /when>
< when test = "criterion.listValue" >
and ${criterion.condition}
< foreach collection = "criterion.value" item = "listItem" open = "(" close = ")" separator = "," >
< /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_log
where user_id =
and order_id =
and money_log_type =
< /select>
< delete id = "deleteByPrimaryKey" parameterType = "com.itheima.shop.pojo.TradeUserMoneyLogKey" >
delete from trade_user_money_log
where user_id =
and order_id =
and money_log_type =
< /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 (
< /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" >
< /if>
< if test = "orderId != null" >
< /if>
< if test = "moneyLogType != null" >
< /if>
< if test = "useMoney != null" >
< /if>
< if test = "createTime != null" >
< /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 =
< /if>
< if test = "record.orderId != null" >
order_id =
< /if>
< if test = "record.moneyLogType != null" >
money_log_type =
< /if>
< if test = "record.useMoney != null" >
use_money =
< /if>
< if test = "record.createTime != null" >
create_time =
< /if>
< /set>
< if test = "_parameter != null" >
< include refid = "Update_By_Example_Where_Clause" />
< /if>
< /update>
< update id = "updateByExample" parameterType = "map" >
update trade_user_money_log
set user_id =
order_id =
money_log_type =
use_money =
create_time =
< 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 =
< /if>
< if test = "createTime != null" >
create_time =
< /if>
< /set>
where user_id =
and order_id =
and money_log_type =
< /update>
< update id = "updateByPrimaryKey" parameterType = "com.itheima.shop.pojo.TradeUserMoneyLog" >
update trade_user_money_log
set use_money =
create_time =
where user_id =
and order_id =
and money_log_type =
< /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
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.type-aliases-package= com.itheima.shop.pojo
mybatis.mapper-locations= classpath:com/itheima/shop/mapper/*Mapper.xml
rocketmq.name-server= 192.168 .25.135:9876; 192.168 .25.138:9876
rocketmq.producer.group = orderProducerGroup
mq.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 {
@Reference
private 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( ) ;
// ms
factory.setReadTimeout( 15000 ) ;
// ms
factory.setConnectTimeout( 15000 ) ;
return factory;
}
}
9.5、创建 配置文件 application.properties
server.host = http://localhost
server.servlet.path = /order-web
server.port = 8080
spring.application.name = dubbo-order-consumer
spring.dubbo.application.id = dubbo-order-consumer
spring.dubbo.application.name = dubbo-order-consumer
spring.dubbo.registry.address = zookeeper://192.168.25.140:2181; zookeeper://192.168.25.140:2182; zookeeper://192.168.25.140:2183
order.port = 8080
shop.order.baseURI = ${server.host} : ${order.port} ${server.servlet.path}
shop.order.confirm = /order/confirm
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 {
@Autowired
private RestTemplate restTemplate;
@Value( "${shop.order.baseURI} " )
private String baseURI;
@Value( "${shop.order.confirm} " )
private String confirmOrderPath;
@Test
public void confirmOrder ( ) {
Long coupouId = 345988230098857984L;
Long goodsId = 345959443973935104L;
Long userId = 345963634385633280L;
TradeOrder order = new TradeOrder( ) ;
order.setGoodsId( goodsId) ;
order.setUserId( userId) ;
order.setCouponId( coupouId) ;
order.setAddress( "北京" ) ;
order.setGoodsNumber( 1 ) ;
order.setGoodsPrice( new BigDecimal( 1000 )) ;
order.setShippingFee( BigDecimal.ZERO) ;
order.setOrderAmount( new BigDecimal( 1000 )) ;
order.setMoneyPaid( new BigDecimal( 100 )) ;
Result result = restTemplate.postForEntity( baseURI + confirmOrderPath, order, Result.class) .getBody( ) ;
System.out.println( result) ;
}
}
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 {
@Reference
private IPayService payService;
@RequestMapping( "/createPayment" )
public Result createPayment( @RequestBody TradePay pay) {
return payService.createPayment( pay) ;
}
@RequestMapping( "/callBackPayment" )
public Result callBackPayment( @RequestBody TradePay pay) throws Exception {
return payService.callbackPayment( pay) ;
}
}
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( ) ;
// ms
factory.setReadTimeout( 15000 ) ;
// ms
factory.setConnectTimeout( 15000 ) ;
return factory;
}
}
10.5、创建 配置文件 application.properties
server.host = http://localhost
server.servlet.path = /pay-web
server.port = 9090
spring.application.name = dubbo-pay-consumer
spring.dubbo.application.id = dubbo-pay-consumer
spring.dubbo.application.name = dubbo-pay-consumer
spring.dubbo.registry.address = zookeeper://192.168.25.140:2181; zookeeper://192.168.25.140:2182; zookeeper://192.168.25.140:2183
pay.port = 9090
shop.pay.baseURI = ${server.host} : ${pay.port} ${server.servlet.path}
shop.pay.createPayment = /pay/createPayment
shop.pay.callbackPayment = /pay/callBackPayment
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 {
@Autowired
private RestTemplate restTemplate;
@Value( "${shop.pay.baseURI} " )
private String baseURI;
@Value( "${shop.pay.createPayment} " )
private String createPaymentPath;
@Value( "${shop.pay.callbackPayment} " )
private String callBackPaymentPath;
@Test
public void createPayment ( ) {
long orderId = 352537369385242624L;
TradePay tradePay = new TradePay( ) ;
tradePay.setOrderId( orderId) ;
tradePay.setPayAmount( new BigDecimal( 880 )) ;
Result result = restTemplate.postForEntity( baseURI + createPaymentPath, tradePay, Result.class) .getBody( ) ;
System.out.println( result) ;
}
@Test
public void callBackPayment ( ) {
long payId = 352542415984402432L;
long orderId = 352537369385242624L;
TradePay tradePay = new TradePay( ) ;
tradePay.setPayId( payId) ;
tradePay.setOrderId( orderId) ;
tradePay.setIsPaid( ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode( )) ;
Result result = restTemplate.postForEntity( baseURI + callBackPaymentPath, tradePay, Result.class) .getBody( ) ;
System.out.println( result) ;
}
}
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 实战:模拟电商网站场景综合案例(二)