Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Y
yudao-cloud
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
hblj
yudao-cloud
Commits
efaeb5b3
提交
efaeb5b3
authored
11月 30, 2020
作者:
YunaiV
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
1. 增加 XXL-Job starter
2. 迁移 pay 服务的 Job 逻辑
上级
04f53da6
隐藏空白字符变更
内嵌
并排
正在显示
48 个修改的文件
包含
598 行增加
和
382 行删除
+598
-382
README.md
README.md
+32
-34
pom.xml
common/mall-spring-boot-starter-xxl-job/pom.xml
+34
-0
XxlJobAutoConfiguration.java
...n/iocoder/mall/xxljob/config/XxlJobAutoConfiguration.java
+56
-0
XxlJobProperties.java
.../java/cn/iocoder/mall/xxljob/config/XxlJobProperties.java
+172
-0
spring.factories
...rter-xxl-job/src/main/resources/META-INF/spring.factories
+2
-0
pom.xml
common/pom.xml
+1
-0
pom.xml
mall-dependencies/pom.xml
+8
-2
OrderMapper.java
...java/cn/iocoder/mall/order/biz/dao/order/OrderMapper.java
+0
-53
OrderMapper.java
.../main/java/cn/iocoder/mall/order/biz/dao/OrderMapper.java
+0
-22
OrderServiceImpl.java
...a/cn/iocoder/mall/order/biz/service/OrderServiceImpl.java
+0
-25
OrderMapper.xml
...er-service-impl/src/main/resources/mapper/OrderMapper.xml
+0
-94
XxlJobConfiguration.java
...a/cn/iocoder/mall/pay/biz/config/XxlJobConfiguration.java
+0
-47
PayTransactionServiceImpl.java
...coder/mall/pay/biz/service/PayTransactionServiceImpl.java
+0
-3
application-test.yaml
...plication/src/main/resources/config/application-test.yaml
+0
-12
pom.xml
pay-service-project/pay-service-app/pom.xml
+6
-0
DubboReferencePool.java
...oder/mall/payservice/common/dubbo/DubboReferencePool.java
+10
-5
AopConfiguration.java
...a/cn/iocoder/mall/payservice/config/AopConfiguration.java
+12
-0
PayNotifyConvert.java
...oder/mall/payservice/convert/notify/PayNotifyConvert.java
+14
-2
PayNotifyTaskDO.java
...yservice/dal/mysql/dataobject/notify/PayNotifyTaskDO.java
+6
-14
PayNotifyTaskMapper.java
...yservice/dal/mysql/mapper/notify/PayNotifyTaskMapper.java
+9
-4
PayNotifyRetryJob.java
...iocoder/mall/payservice/job/notify/PayNotifyRetryJob.java
+22
-23
package-info.java
...ain/java/cn/iocoder/mall/payservice/job/package-info.java
+1
-0
AbstractPayNotifySuccessMQConsumer.java
...rvice/mq/consumer/AbstractPayNotifySuccessMQConsumer.java
+35
-12
PayRefundSuccessMQConsumer.java
...ll/payservice/mq/consumer/PayRefundSuccessMQConsumer.java
+10
-2
PayTransactionSuccessMQConsumer.java
...yservice/mq/consumer/PayTransactionSuccessMQConsumer.java
+10
-2
PayMQProducer.java
...cn/iocoder/mall/payservice/mq/producer/PayMQProducer.java
+2
-4
PayNotifyService.java
...oder/mall/payservice/service/notify/PayNotifyService.java
+4
-0
PayNotifyServiceImpl.java
.../payservice/service/notify/impl/PayNotifyServiceImpl.java
+14
-5
application-dev.yaml
...t/pay-service-app/src/main/resources/application-dev.yaml
+11
-1
application-local.yaml
...pay-service-app/src/main/resources/application-local.yaml
+17
-1
DubboGenericInvokerTest.java
...mall/payservice/common/dubbo/DubboGenericInvokerTest.java
+21
-4
package-info.java
.../java/cn/iocoder/mall/payservice/common/package-info.java
+1
-0
application-dev.yaml
...oduct-service-app/src/main/resources/application-dev.yaml
+1
-1
application-local.yaml
...uct-service-app/src/main/resources/application-local.yaml
+1
-1
application-dev.yaml
...otion-service-app/src/main/resources/application-dev.yaml
+1
-1
application-local.yaml
...ion-service-app/src/main/resources/application-local.yaml
+1
-1
application-dev.yaml
...ystem-service-app/src/main/resources/application-dev.yaml
+1
-1
application-local.yaml
...tem-service-app/src/main/resources/application-local.yaml
+1
-1
TradeOrderRpc.java
...cn/iocoder/mall/tradeservice/rpc/order/TradeOrderRpc.java
+11
-0
TradeOrderItemMapper.java
...eservice/dal/mysql/mapper/order/TradeOrderItemMapper.java
+5
-0
TradeOrderMapper.java
...tradeservice/dal/mysql/mapper/order/TradeOrderMapper.java
+6
-0
TradeOrderRpcImpl.java
...ocoder/mall/tradeservice/rpc/order/TradeOrderRpcImpl.java
+6
-0
TradeOrderService.java
...er/mall/tradeservice/service/order/TradeOrderService.java
+8
-0
TradeOrderServiceImpl.java
...radeservice/service/order/impl/TradeOrderServiceImpl.java
+37
-1
application-dev.yaml
...trade-service-app/src/main/resources/application-dev.yaml
+1
-1
application-local.yaml
...ade-service-app/src/main/resources/application-local.yaml
+6
-1
application-dev.yaml
.../user-service-app/src/main/resources/application-dev.yaml
+1
-1
application-local.yaml
...ser-service-app/src/main/resources/application-local.yaml
+1
-1
没有找到文件。
README.md
浏览文件 @
efaeb5b3
...
...
@@ -34,21 +34,19 @@
>
> 迫切希望,有前端能力不错的小伙伴,加入我们,一起来完善「芋道商城」。
## H5 商城
体验传送门:
<http://h5.shop.iocoder.cn>
## 管理后台
*2M 带宽小水管,访问略微有点慢*
体验传送门:
<http://dashboard.shop.iocoder.cn>


##
管理后台
##
H5 商城
体验传送门:
<http://
dashboard
.shop.iocoder.cn>
体验传送门:
<http://
h5
.shop.iocoder.cn>
*2M 带宽小水管,访问略微有点慢*


## 其它演示
...
...
@@ -81,10 +79,10 @@
**XXL-Job Console**
*
地址:
<http://job.shop.iocoder.cn>
*
管理员账号:admin /
23366
6
*
地址:
<http://
xxl-
job.shop.iocoder.cn>
*
管理员账号:admin /
12345
6
> 教程:[《芋道
RocketMQ
安装部署》](http://www.iocoder.cn/XXL-JOB/install/?onemall)
> 教程:[《芋道
XXL-Job
安装部署》](http://www.iocoder.cn/XXL-JOB/install/?onemall)
**Sentinel Console**
...
...
@@ -107,33 +105,35 @@ TODO 此处应有一个架构图的装逼 JPG 图。
| 模块 | 名称 | 端口 | |
| --- | --- | --- | --- |
|
`admin-web`
| 【前端】管理后台 | HTTP 8080 | |
|
`mobile-web`
| 【前端】商城 H5 | HTTP 8000 | |
|
`system-application`
| 管理员 HTTP 服务 | HTTP 18083 |
[
接口文档
](
http://api.shop.iocoder.cn/admin-api/doc.html
)
|
|
`user-application`
| 用户 HTTP 服务 | HTTP 18082 |
[
接口文档
](
http://api.shop.iocoder.cn/user-api/doc.html
)
|
|
`product-application`
| 商品 HTTP 服务 | HTTP 18081 |
[
接口文档
](
http://api.shop.iocoder.cn/product-api/doc.html
)
|
|
`pay-application`
| 支付 HTTP 服务 | HTTP 18084 |
[
接口文档
](
http://api.shop.iocoder.cn/pay-api/doc.html
)
|
|
`promotion-application`
| 促销 HTTP 服务 | HTTP 18085 |
[
接口文档
](
http://api.shop.iocoder.cn/promotion-api/doc.html
)
|
|
`search-application`
| 搜索 HTTP 服务 | HTTP 18086 |
[
接口文档
](
http://api.shop.iocoder.cn/search-api/doc.html
)
|
|
`order-application`
| 订单 HTTP 服务 | HTTP 18088 |
[
接口文档
](
http://api.shop.iocoder.cn/order-api/doc.html
)
|
|
[
`admin-dashboard-vue`
](
https://github.com/YunaiV/onemall-web/tree/master/admin-dashboard-vue
)
| 【前端】管理后台 | HTTP 9527 | |
|
[
`user-dashboard-vue`
](
https://github.com/YunaiV/onemall-web/tree/master/user-h5-vue
)
| 【前端】商城平台 | HTTP 8080 | |
| | | |
| | | |
|
`management-web-app`
| 【后端】管理平台 HTTP 服务 | HTTP 18083 |
[
接口文档
](
http://api-dashboard.shop.iocoder.cn/management-api/doc.html
)
|
|
`shop-web-app`
| 【后端】商城平台 HTTP 服务 | HTTP 18084 |
[
接口文档
](
http://api-h5.shop.iocoder.cn/shop-api/doc.html
)
|
| | | |
| | | |
|
`system-service-project`
| 系统 RPC 服务 | 随机 |
|
`user-service-project`
| 用户 RPC 服务 | 随机 | |
|
`promotion-service-project`
| 营销 RPC 服务 | 随机 | |
|
`pay-service-project`
| 支付 RPC 服务 | 随机 | |
|
`trade-service-project`
| 交易 RPC 服务 | 随机 | |
|
`product-service-project`
| 商品 RPC 服务 | 随机 | |
|
`search-service-project`
| 搜索å RPC 服务 | 随机 | |
-------
后端项目,目前的项目结构如下:
```
Java
[-] xxx
├──[-] xxx-application // 提供对外 HTTP API 。
├──[-] xxx-service-api // 提供 Dubbo 服务 API 。
├──[-] xxx-service-impl // 提供 Dubbo 服务 Service 实现。
```
[-] xxx-web-app // 提供对外 HTTP API。
考虑到大多数公司,无需拆分的特别细,并且过多 JVM 带来的服务器成本。所以目前的设定是:
*
`xxx-service-impl`
内嵌在
`xxx-application`
中运行。
*
MQ 消费者、定时器执行器,内嵌在
`xxx-service-impl`
中运行。
[-] xxx-service-project
├──[-] xxx-service-api // 提供对内 RPC API 。
├──[-] xxx-service-app // 提供对内 RPC 实现。
├──[-] xxx-service-integration-test // 集成测试。
```
也就是说,一个
`xxx-application`
启动后,该模块就完整启动了。
## 技术栈
...
...
@@ -165,8 +165,6 @@ TODO 此处应有一个架构图的装逼 JPG 图。
### 前端
商城 H5 和管理后台,分别采用了 Vue 和 React ,基于其适合的场景考虑。具体的,可以看看
[
《为什么 React 比 Vue 更适合大型应用?》
](
https://www.zhihu.com/question/314761485/answer/615318460
)
的讨论。
**商城 H5**
| 框架 | 说明 | 版本 |
...
...
@@ -178,8 +176,8 @@ TODO 此处应有一个架构图的装逼 JPG 图。
| 框架 | 说明 | 版本 |
| --- | --- | --- |
|
[
React
](
https://reactjs.org/
)
| JavaScript 框架 | 16.7.0
|
|
[
Ant Design
](
https://ant.design/docs/react/introduce-cn
)
| React UI 组件库 | 3.13.0
|
|
[
Vue
](
https://cn.vuejs.org/index.html
)
| JavaScript 框架 | 2.5.17
|
|
[
Vue Element Admin
](
https://ant.design/docs/react/introduce-cn
)
| 后台前端解决方案 | -
|
### 监控
...
...
common/mall-spring-boot-starter-xxl-job/pom.xml
0 → 100644
浏览文件 @
efaeb5b3
<?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>
common
</artifactId>
<groupId>
cn.iocoder.mall
</groupId>
<version>
1.0-SNAPSHOT
</version>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<artifactId>
mall-spring-boot-starter-xxl-job
</artifactId>
<dependencies>
<!-- Spring 核心 -->
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-configuration-processor
</artifactId>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter
</artifactId>
<optional>
true
</optional>
</dependency>
<!-- Job 相关 -->
<dependency>
<groupId>
com.xuxueli
</groupId>
<artifactId>
xxl-job-core
</artifactId>
</dependency>
</dependencies>
</project>
common/mall-spring-boot-starter-xxl-job/src/main/java/cn/iocoder/mall/xxljob/config/XxlJobAutoConfiguration.java
0 → 100644
浏览文件 @
efaeb5b3
package
cn
.
iocoder
.
mall
.
xxljob
.
config
;
import
com.xxl.job.core.executor.XxlJobExecutor
;
import
com.xxl.job.core.executor.impl.XxlJobSpringExecutor
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnClass
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.boot.context.properties.EnableConfigurationProperties
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
java.util.Objects
;
/**
* XXL-Job 自动配置类
*/
@Configuration
@ConditionalOnClass
(
XxlJobSpringExecutor
.
class
)
@ConditionalOnProperty
(
prefix
=
"xxl.job"
,
name
=
"enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
true
)
@EnableConfigurationProperties
({
XxlJobProperties
.
class
})
public
class
XxlJobAutoConfiguration
{
private
static
final
Logger
LOGGER
=
LoggerFactory
.
getLogger
(
XxlJobAutoConfiguration
.
class
);
private
final
XxlJobProperties
properties
;
public
XxlJobAutoConfiguration
(
XxlJobProperties
properties
)
{
this
.
properties
=
properties
;
}
@Bean
@ConditionalOnMissingBean
public
XxlJobExecutor
xxlJobExecutor
()
{
LOGGER
.
info
(
"初始化 XXL-Job 执行器的配置"
);
// 参数校验
XxlJobProperties
.
AdminProperties
admin
=
this
.
properties
.
getAdmin
();
XxlJobProperties
.
ExecutorProperties
executor
=
this
.
properties
.
getExecutor
();
Objects
.
requireNonNull
(
admin
,
"xxl job admin properties must not be null."
);
Objects
.
requireNonNull
(
executor
,
"xxl job executor properties must not be null."
);
// 初始化执行器
XxlJobExecutor
xxlJobExecutor
=
new
XxlJobSpringExecutor
();
xxlJobExecutor
.
setIp
(
executor
.
getIp
());
xxlJobExecutor
.
setPort
(
executor
.
getPort
());
xxlJobExecutor
.
setAppname
(
executor
.
getAppName
());
xxlJobExecutor
.
setLogPath
(
executor
.
getLogPath
());
xxlJobExecutor
.
setLogRetentionDays
(
executor
.
getLogRetentionDays
());
xxlJobExecutor
.
setAdminAddresses
(
admin
.
getAddresses
());
xxlJobExecutor
.
setAccessToken
(
this
.
properties
.
getAccessToken
());
return
xxlJobExecutor
;
}
}
common/mall-spring-boot-starter-xxl-job/src/main/java/cn/iocoder/mall/xxljob/config/XxlJobProperties.java
0 → 100644
浏览文件 @
efaeb5b3
package
cn
.
iocoder
.
mall
.
xxljob
.
config
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
/**
* XXL-Job 配置类
*/
@ConfigurationProperties
(
"xxl.job"
)
public
class
XxlJobProperties
{
/**
* 是否开启,默认为 true 关闭
*/
private
Boolean
enabled
=
true
;
/**
* 访问令牌
*/
private
String
accessToken
;
/**
* 控制器配置
*/
private
AdminProperties
admin
;
/**
* 执行器配置
*/
private
ExecutorProperties
executor
;
public
Boolean
getEnabled
()
{
return
enabled
;
}
public
void
setEnabled
(
Boolean
enabled
)
{
if
(
enabled
!=
null
)
{
this
.
enabled
=
enabled
;
}
}
public
String
getAccessToken
()
{
return
accessToken
;
}
public
void
setAccessToken
(
String
accessToken
)
{
if
(
accessToken
!=
null
&&
accessToken
.
trim
().
length
()
>
0
)
{
this
.
accessToken
=
accessToken
;
}
}
public
AdminProperties
getAdmin
()
{
return
admin
;
}
public
void
setAdmin
(
AdminProperties
admin
)
{
this
.
admin
=
admin
;
}
public
ExecutorProperties
getExecutor
()
{
return
executor
;
}
public
void
setExecutor
(
ExecutorProperties
executor
)
{
this
.
executor
=
executor
;
}
/**
* XXL-Job 调度器配置类
*/
public
static
class
AdminProperties
{
/**
* 调度器地址
*/
private
String
addresses
;
public
String
getAddresses
()
{
return
addresses
;
}
public
void
setAddresses
(
String
addresses
)
{
this
.
addresses
=
addresses
;
}
@Override
public
String
toString
()
{
return
"AdminProperties{"
+
"addresses='"
+
addresses
+
'\''
+
'}'
;
}
}
/**
* XXL-Job 执行器配置类
*/
public
static
class
ExecutorProperties
{
/**
* 默认端口
*
* 这里使用 -1 表示随机
*/
private
static
final
Integer
PORT_DEFAULT
=
-
1
;
/**
* 默认日志保留天数
*
* 默认为 -1,不清理,永久保留
*/
private
static
final
Integer
LOG_RETENTION_DAYS_DEFAULT
=
-
1
;
/**
* 应用名
*/
private
String
appName
;
/**
* 执行器的 IP
*/
private
String
ip
;
/**
* 执行器的 Port
*/
private
Integer
port
=
PORT_DEFAULT
;
/**
* 日志地址
*/
private
String
logPath
;
/**
* 日志保留天数
*/
private
Integer
logRetentionDays
=
LOG_RETENTION_DAYS_DEFAULT
;
public
String
getAppName
()
{
return
appName
;
}
public
void
setAppName
(
String
appName
)
{
this
.
appName
=
appName
;
}
public
String
getLogPath
()
{
return
logPath
;
}
public
void
setLogPath
(
String
logPath
)
{
this
.
logPath
=
logPath
;
}
public
String
getIp
()
{
return
ip
;
}
public
void
setIp
(
String
ip
)
{
this
.
ip
=
ip
;
}
public
Integer
getPort
()
{
return
port
;
}
public
void
setPort
(
Integer
port
)
{
this
.
port
=
port
;
}
public
Integer
getLogRetentionDays
()
{
return
logRetentionDays
;
}
public
void
setLogRetentionDays
(
Integer
logRetentionDays
)
{
this
.
logRetentionDays
=
logRetentionDays
;
}
}
}
common/mall-spring-boot-starter-xxl-job/src/main/resources/META-INF/spring.factories
0 → 100644
浏览文件 @
efaeb5b3
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.iocoder.mall.xxljob.config.XxlJobAutoConfiguration
common/pom.xml
浏览文件 @
efaeb5b3
...
...
@@ -24,6 +24,7 @@
<module>
mall-spring-boot-starter-dubbo
</module>
<module>
mall-spring-boot-starter-system-error-code
</module>
<module>
mall-spring-boot-starter-rocketmq
</module>
<module>
mall-spring-boot-starter-xxl-job
</module>
</modules>
<dependencyManagement>
...
...
mall-dependencies/pom.xml
浏览文件 @
efaeb5b3
...
...
@@ -43,9 +43,9 @@
<!-- RPC 相关 -->
<dubbo.version>
2.7.7
</dubbo.version>
<!-- MQ 相关 -->
<rocketmq-spring-boot-starter.version>
2.1.
0
</rocketmq-spring-boot-starter.version>
<rocketmq-spring-boot-starter.version>
2.1.
1
</rocketmq-spring-boot-starter.version>
<!-- Job 相关 -->
<xxl-job.version>
2.
0.1
</xxl-job.version>
<xxl-job.version>
2.
2.0
</xxl-job.version>
<!-- Transaction 相关 -->
<seata.version>
1.1.0
</seata.version>
<!-- 云服务相关 -->
...
...
@@ -249,6 +249,12 @@
<version>
${xxl-job.version}
</version>
</dependency>
<dependency>
<groupId>
cn.iocoder.mall
</groupId>
<artifactId>
mall-spring-boot-starter-xxl-job
</artifactId>
<version>
1.0-SNAPSHOT
</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-client -->
<!-- <dependency>-->
<!-- <groupId>com.alibaba.nacos</groupId>-->
...
...
moved/order/order-biz/src/main/java/cn/iocoder/mall/order/biz/dao/order/OrderMapper.java
deleted
100644 → 0
浏览文件 @
04f53da6
package
cn
.
iocoder
.
mall
.
order
.
biz
.
dao
.
order
;
import
cn.iocoder.mall.order.biz.dataobject.OrderDO
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
org.springframework.stereotype.Repository
;
/**
* 订单 mapper
*
* @author Sin
* @time 2019-03-16 15:09
*/
@Repository
public
interface
OrderMapper
extends
BaseMapper
<
OrderDO
>
{
// /**
// * 更新 - 根据 id 更新
// *
// * @param orderDO
// * @return
// */
// int updateById(OrderDO orderDO);
//
// int updateByIdAndStatus(@Param("id") Integer id,
// @Param("status") Integer status,
// @Param("updateObj") OrderDO updateObj);
//
// /**
// * 查询 - 根据id 查询
// *
// * @param id
// * @return
// */
// OrderDO selectById(
// @Param("id") Integer id
// );
//
// /**
// * 查询 - 后台分页page
// *
// * @param orderQueryDTO
// * @return
// */
// int selectPageCount(OrderQueryDTO orderQueryDTO);
//
// /**
// * 查询 - 后台分页page
// *
// * @param orderQueryDTO
// * @return
// */
// List<OrderDO> selectPage(OrderQueryDTO orderQueryDTO);
}
moved/order/order-service-impl/src/main/java/cn/iocoder/mall/order/biz/dao/OrderMapper.java
浏览文件 @
efaeb5b3
...
...
@@ -17,28 +17,6 @@ import java.util.List;
@Repository
public
interface
OrderMapper
extends
BaseMapper
<
OrderDO
>
{
/**
* 更新 - 根据 id 更新
*
* @param orderDO
* @return
*/
int
updateById
(
OrderDO
orderDO
);
int
updateByIdAndStatus
(
@Param
(
"id"
)
Integer
id
,
@Param
(
"status"
)
Integer
status
,
@Param
(
"updateObj"
)
OrderDO
updateObj
);
/**
* 查询 - 根据id 查询
*
* @param id
* @return
*/
OrderDO
selectById
(
@Param
(
"id"
)
Integer
id
);
/**
* 查询 - 后台分页page
*
...
...
moved/order/order-service-impl/src/main/java/cn/iocoder/mall/order/biz/service/OrderServiceImpl.java
浏览文件 @
efaeb5b3
...
...
@@ -326,31 +326,6 @@ public class OrderServiceImpl implements OrderService {
return
CommonResult
.
success
(
null
);
}
@Override
public
String
updatePaySuccess
(
String
orderId
,
Integer
payAmount
)
{
OrderDO
order
=
orderMapper
.
selectById
(
Integer
.
valueOf
(
orderId
));
if
(
order
==
null
)
{
// 订单不存在
return
ServiceExceptionUtil
.
error
(
OrderErrorCodeEnum
.
ORDER_NOT_EXISTENT
.
getCode
()).
getMessage
();
}
if
(!
order
.
getStatus
().
equals
(
OrderStatusEnum
.
WAITING_PAYMENT
.
getValue
()))
{
// 状态不处于等待支付
return
ServiceExceptionUtil
.
error
(
OrderErrorCodeEnum
.
ORDER_STATUS_NOT_WAITING_PAYMENT
.
getCode
()).
getMessage
();
}
if
(!
order
.
getPresentPrice
().
equals
(
payAmount
))
{
// 支付金额不正确
return
ServiceExceptionUtil
.
error
(
OrderErrorCodeEnum
.
ORDER_PAY_AMOUNT_ERROR
.
getCode
()).
getMessage
();
}
// 更新 OrderDO 状态为已支付,等待发货
OrderDO
updateOrderObj
=
new
OrderDO
()
.
setStatus
(
OrderStatusEnum
.
WAIT_SHIPMENT
.
getValue
())
.
setPayAmount
(
payAmount
)
.
setPaymentTime
(
new
Date
());
int
updateCount
=
orderMapper
.
updateByIdAndStatus
(
order
.
getId
(),
order
.
getStatus
(),
updateOrderObj
);
if
(
updateCount
<=
0
)
{
return
ServiceExceptionUtil
.
error
(
OrderErrorCodeEnum
.
ORDER_STATUS_NOT_WAITING_PAYMENT
.
getCode
()).
getMessage
();
}
// TODO FROM 芋艿 to 小范,把更新 OrderItem 给补全。
return
"success"
;
}
@Override
public
CommonResult
listenerConfirmGoods
()
{
return
null
;
...
...
moved/order/order-service-impl/src/main/resources/mapper/OrderMapper.xml
浏览文件 @
efaeb5b3
...
...
@@ -2,100 +2,6 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"cn.iocoder.mall.order.biz.dao.order.OrderMapper"
>
<sql
id=
"FIELDS"
>
id, user_id, order_no, buy_price, discount_price, logistics_price, present_price, pay_amount,
payment_time, delivery_time, receiver_time, closing_time,
has_return_exchange,
status, remark, create_time, update_time, `deleted`
</sql>
<sql
id=
"updateFieldSql"
>
<set>
<if
test=
"orderNo != null"
>
, order_no = #{orderNo}
</if>
<if
test=
"buyPrice != null"
>
, buy_price = #{buyPrice}
</if>
<if
test=
"discountPrice != null"
>
, discount_price = #{discountPrice}
</if>
<if
test=
"logisticsPrice != null"
>
, logistics_price = #{logisticsPrice}
</if>
<if
test=
"logisticsPrice != null"
>
, logistics_price = #{logisticsPrice}
</if>
<if
test=
"presentPrice != null"
>
, present_price = #{presentPrice}
</if>
<if
test=
"payAmount != null"
>
, pay_amount = #{payAmount}
</if>
<if
test=
"deliveryTime != null"
>
, delivery_time = #{deliveryTime}
</if>
<if
test=
"paymentTime != null"
>
, payment_time = #{paymentTime}
</if>
<if
test=
"receiverTime != null"
>
, receiver_time = #{receiverTime}
</if>
<if
test=
"closingTime != null"
>
, closing_time = #{closingTime}
</if>
<if
test=
"hasReturnExchange != null"
>
, has_return_exchange = #{hasReturnExchange}
</if>
<if
test=
"status != null"
>
, status = #{status}
</if>
<if
test=
"remark != null"
>
, remark = #{remark}
</if>
<if
test=
"deleted != null"
>
, `deleted` = #{deleted}
</if>
<if
test=
"createTime != null"
>
, create_time = #{createTime}
</if>
<if
test=
"updateTime != null"
>
, update_time = #{updateTime}
</if>
</set>
</sql>
<update
id=
"updateById"
parameterType=
"OrderDO"
>
UPDATE `orders`
<include
refid=
"updateFieldSql"
/>
WHERE id = #{id}
</update>
<update
id=
"updateByIdAndStatus"
>
UPDATE `orders`
<set>
<if
test=
"updateObj.payAmount != null"
>
, pay_amount = #{updateObj.payAmount}
</if>
<if
test=
"updateObj.paymentTime != null"
>
, payment_time = #{updateObj.paymentTime}
</if>
<if
test=
"updateObj.status != null"
>
, status = #{updateObj.status}
</if>
</set>
WHERE id = #{id}
AND status = #{status}
</update>
<select
id=
"selectById"
resultType=
"cn.iocoder.mall.order.biz.dataobject.OrderDO"
>
SELECT
<include
refid=
"FIELDS"
/>
FROM `orders`
WHERE id = #{id}
</select>
<sql
id=
"selectWhere"
>
<if
test=
"status != null"
>
AND `status` = #{status}
...
...
moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/config/XxlJobConfiguration.java
deleted
100644 → 0
浏览文件 @
04f53da6
package
cn
.
iocoder
.
mall
.
pay
.
biz
.
config
;
import
com.xxl.job.core.executor.impl.XxlJobSpringExecutor
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Profile
;
@Configuration
@Profile
(
"dev"
)
public
class
XxlJobConfiguration
{
private
Logger
logger
=
LoggerFactory
.
getLogger
(
XxlJobConfiguration
.
class
);
@Value
(
"${xxl.job.admin.addresses}"
)
private
String
adminAddresses
;
@Value
(
"${xxl.job.executor.appname}"
)
private
String
appName
;
@Value
(
"${xxl.job.executor.ip}"
)
private
String
ip
;
@Value
(
"${xxl.job.executor.port}"
)
private
int
port
;
@Value
(
"${xxl.job.accessToken}"
)
private
String
accessToken
;
@Value
(
"${xxl.job.executor.logpath}"
)
private
String
logPath
;
@Value
(
"${xxl.job.executor.logretentiondays}"
)
private
int
logRetentionDays
;
@Bean
(
initMethod
=
"start"
,
destroyMethod
=
"destroy"
)
public
XxlJobSpringExecutor
xxlJobExecutor
()
{
logger
.
info
(
">>>>>>>>>>> xxl-job config init."
);
XxlJobSpringExecutor
xxlJobSpringExecutor
=
new
XxlJobSpringExecutor
();
xxlJobSpringExecutor
.
setAdminAddresses
(
adminAddresses
);
xxlJobSpringExecutor
.
setAppName
(
appName
);
xxlJobSpringExecutor
.
setIp
(
ip
);
xxlJobSpringExecutor
.
setPort
(
port
);
xxlJobSpringExecutor
.
setAccessToken
(
accessToken
);
xxlJobSpringExecutor
.
setLogPath
(
logPath
);
xxlJobSpringExecutor
.
setLogRetentionDays
(
logRetentionDays
);
return
xxlJobSpringExecutor
;
}
}
moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/service/PayTransactionServiceImpl.java
浏览文件 @
efaeb5b3
...
...
@@ -80,7 +80,4 @@ public class PayTransactionServiceImpl implements PayTransactionService {
return
null
;
}
}
moved/pay/pay-application/src/main/resources/config/application-test.yaml
deleted
100644 → 0
浏览文件 @
04f53da6
# xxl-job
xxl
:
job
:
admin
:
addresses
:
http://s1.iocoder.cn:18079/
executor
:
appname
:
pay-job-executor
ip
:
port
:
0
logpath
:
/Users/yunai/logs/xxl-job/
logretentiondays
:
1
accessToken
:
pay-service-project/pay-service-app/pom.xml
浏览文件 @
efaeb5b3
...
...
@@ -37,6 +37,12 @@
<artifactId>
mall-spring-boot-starter-rocketmq
</artifactId>
</dependency>
<!-- Job 相关 -->
<dependency>
<groupId>
cn.iocoder.mall
</groupId>
<artifactId>
mall-spring-boot-starter-xxl-job
</artifactId>
</dependency>
<!-- Registry 和 Config 相关 -->
<dependency>
<groupId>
com.alibaba.cloud
</groupId>
...
...
pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/common/dubbo/DubboReferencePool.java
浏览文件 @
efaeb5b3
...
...
@@ -46,9 +46,15 @@ public class DubboReferencePool {
@Value
(
"${dubbo.application.name}"
)
private
String
dubboApplicationName
;
public
ReferenceMeta
getReferenceMeta
(
String
notifyUrl
)
{
DubboReferencePool
.
ReferenceMeta
referenceMeta
=
referenceMetaCache
.
getUnchecked
(
notifyUrl
);
Assert
.
notNull
(
referenceMeta
,
String
.
format
(
"notifyUrl(%s) 不存在对应的 ReferenceMeta 对象"
,
notifyUrl
));
return
referenceMeta
;
}
private
ReferenceMeta
createGenericService
(
String
notifyUrl
)
{
// 使用 # 号分隔,格式为 服务名#方法名#版本号
List
<
String
>
notifyUrlParts
=
StringUtils
.
split
(
notifyUrl
,
"#"
);
List
<
String
>
notifyUrlParts
=
this
.
parseNotifyUrl
(
notifyUrl
);
// 创建 ApplicationConfig 对象
ApplicationConfig
application
=
new
ApplicationConfig
();
application
.
setName
(
dubboApplicationName
);
...
...
@@ -69,10 +75,9 @@ public class DubboReferencePool {
return
new
ReferenceMeta
(
reference
,
genericService
,
notifyUrlParts
.
get
(
1
));
}
public
ReferenceMeta
getReferenceMeta
(
String
notifyUrl
)
{
DubboReferencePool
.
ReferenceMeta
referenceMeta
=
referenceMetaCache
.
getUnchecked
(
notifyUrl
);
Assert
.
notNull
(
referenceMeta
,
String
.
format
(
"notifyUrl(%s) 不存在对应的 ReferenceMeta 对象"
,
notifyUrl
));
return
referenceMeta
;
// TODO 芋艿,后续重构成一个对象
private
List
<
String
>
parseNotifyUrl
(
String
notifyUrl
)
{
return
StringUtils
.
split
(
notifyUrl
,
"#"
);
}
}
pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/config/AopConfiguration.java
0 → 100644
浏览文件 @
efaeb5b3
package
cn
.
iocoder
.
mall
.
payservice
.
config
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.EnableAspectJAutoProxy
;
/**
* Spring Aop 配置类
*/
@Configuration
@EnableAspectJAutoProxy
(
proxyTargetClass
=
true
,
exposeProxy
=
true
)
public
class
AopConfiguration
{
}
pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/convert/notify/PayNotifyConvert.java
浏览文件 @
efaeb5b3
...
...
@@ -4,6 +4,8 @@ import cn.iocoder.mall.payservice.dal.mysql.dataobject.notify.PayNotifyTaskDO;
import
cn.iocoder.mall.payservice.mq.producer.message.PayRefundSuccessMessage
;
import
cn.iocoder.mall.payservice.mq.producer.message.PayTransactionSuccessMessage
;
import
org.mapstruct.Mapper
;
import
org.mapstruct.Mapping
;
import
org.mapstruct.Mappings
;
import
org.mapstruct.factory.Mappers
;
@Mapper
...
...
@@ -11,8 +13,18 @@ public interface PayNotifyConvert {
PayNotifyConvert
INSTANCE
=
Mappers
.
getMapper
(
PayNotifyConvert
.
class
);
PayTransactionSuccessMessage
convertTransaction
(
PayNotifyTaskDO
payTransactionNotifyTaskDO
);
@Mappings
({
@Mapping
(
source
=
"transaction.transactionId"
,
target
=
"transactionId"
),
@Mapping
(
source
=
"transaction.orderId"
,
target
=
"orderId"
),
})
PayTransactionSuccessMessage
convertTransaction
(
PayNotifyTaskDO
entity
);
@Mappings
({
@Mapping
(
source
=
"refund.transactionId"
,
target
=
"transactionId"
),
@Mapping
(
source
=
"refund.orderId"
,
target
=
"orderId"
),
@Mapping
(
source
=
"refund.refundId"
,
target
=
"refundId"
),
})
PayRefundSuccessMessage
convertRefund
(
PayNotifyTaskDO
entity
);
PayRefundSuccessMessage
convertRefund
(
PayNotifyTaskDO
payTransactionNotifyTaskDO
);
}
pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/dal/mysql/dataobject/notify/PayNotifyTaskDO.java
浏览文件 @
efaeb5b3
...
...
@@ -5,7 +5,6 @@ import cn.iocoder.mall.payservice.dal.mysql.dataobject.transaction.PayTransactio
import
cn.iocoder.mall.payservice.dal.mysql.dataobject.transaction.PayTransactionExtensionDO
;
import
cn.iocoder.mall.payservice.enums.notify.PayNotifyStatusEnum
;
import
cn.iocoder.mall.payservice.enums.notify.PayNotifyType
;
import
cn.iocoder.mall.payservice.service.transaction.PayTransactionService
;
import
com.baomidou.mybatisplus.annotation.TableField
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler
;
...
...
@@ -56,25 +55,18 @@ public class PayNotifyTaskDO extends DeletableDO {
* 外键 {@link PayNotifyStatusEnum}
*/
private
Integer
status
;
/**
* 是否激活中,即处于正在 MQ 异步通知中
*
* @see cn.iocoder.mall.payservice.job.notify.PayNotifyRetryJob
*/
private
Boolean
active
;
/**
* 下一次通知时间
*/
private
Date
nextNotifyTime
;
/**
* 最后一次执行时间
*
* 这个字段,需要结合 {@link #nextNotifyTime} 一起使用。
*
* 1. 初始时,{@link PayTransactionService#updateTransactionPaySuccess(Integer, String)}
* nextNotifyTime 为当前时间 + 15 秒
* lastExecuteTime 为空
* 并发送给 MQ ,执行执行
*
* 2. MQ 消费时,更新 lastExecuteTime 为当时时间
*
* 3. 定时任务,扫描 nextNotifyTime < lastExecuteTime 的任务
* nextNotifyTime 为当前时间 + N 秒。具体的 N ,由第几次通知决定
* lastExecuteTime 为当前时间
*/
private
Date
lastExecuteTime
;
/**
...
...
pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/dal/mysql/mapper/notify/PayNotifyTaskMapper.java
浏览文件 @
efaeb5b3
...
...
@@ -16,16 +16,21 @@ public interface PayNotifyTaskMapper extends BaseMapper<PayNotifyTaskDO> {
*
* 1. status 非成功
* 2. nextNotifyTime 小于当前时间
* 3.
lastExecuteTime > nextNotifyTime
* 3.
active 为 false 并未正在执行中
*
* @return PayTransactionNotifyTaskDO 数组
*/
default
List
<
PayNotifyTaskDO
>
selectListByNotify
()
{
return
selectList
(
new
QueryWrapper
<
PayNotifyTaskDO
>()
.
in
(
"status"
,
PayNotifyStatusEnum
.
WAITING
.
get
Name
(),
PayNotifyStatusEnum
.
REQUEST_SUCCESS
.
getName
(),
PayNotifyStatusEnum
.
REQUEST_FAILURE
.
get
Name
())
.
in
(
"status"
,
PayNotifyStatusEnum
.
WAITING
.
get
Status
(),
PayNotifyStatusEnum
.
REQUEST_SUCCESS
.
getStatus
(),
PayNotifyStatusEnum
.
REQUEST_FAILURE
.
get
Status
())
.
le
(
"next_notify_time"
,
"NOW()"
)
.
gt
(
"last_execute_time"
,
"next_notify_time"
));
.
eq
(
"active"
,
Boolean
.
FALSE
));
}
default
int
update
(
PayNotifyTaskDO
update
,
Integer
whereNotifyTimes
)
{
return
update
(
update
,
new
QueryWrapper
<
PayNotifyTaskDO
>()
.
eq
(
"id"
,
update
.
getId
()).
eq
(
"notify_times"
,
whereNotifyTimes
));
}
//
...
...
moved/pay/pay-application/src/main/java/cn/iocoder/mall/pay/biz/job/PayNotif
yJob.java
→
pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/job/notify/PayNotifyRetr
yJob.java
浏览文件 @
efaeb5b3
package
cn
.
iocoder
.
mall
.
pay
.
biz
.
job
;
package
cn
.
iocoder
.
mall
.
pay
service
.
job
.
notify
;
import
cn.iocoder.mall.pay
.biz.dao.PayNotifyTaskMapper
;
import
cn.iocoder.mall.pay
.biz.dataobject.PayNotifyTaskDO
;
import
cn.iocoder.mall.pay
.biz.service.PayNotifyServiceImpl
;
import
cn.iocoder.mall.pay
service.dal.mysql.dataobject.notify.PayNotifyTaskDO
;
import
cn.iocoder.mall.pay
service.dal.mysql.mapper.notify.PayNotifyTaskMapper
;
import
cn.iocoder.mall.pay
service.service.notify.PayNotifyService
;
import
com.xxl.job.core.biz.model.ReturnT
;
import
com.xxl.job.core.handler.IJobHandler
;
import
com.xxl.job.core.handler.annotation.
JobHandler
;
import
org.apache.rocketmq.spring.core.RocketMQTemplate
;
import
com.xxl.job.core.handler.annotation.
XxlJob
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Component
;
import
javax.annotation.Resource
;
import
java.util.Date
;
import
java.util.List
;
/**
* 支付通知重试 Job
*
* 由于 RocketMQ 不支持指定时间的延迟消息,所以我们需要通过 Job 扫描到达 {@link PayNotifyTaskDO#getNextNotifyTime()} 时间的任务。
* 扫描到后,通过发送 MQ 去异步通知,提高通知效率。
*
* 考虑到 MQ 执行可能存在延迟的情况,导致一个 {@link PayNotifyTaskDO} 同时触发多个通知,通过 {@link PayNotifyTaskDO#getActive()} 标记解决。
*/
@Component
@
JobHandler
(
value
=
"payTransactionNotifyJob"
)
public
class
PayNotifyJob
extends
IJobHandler
{
@
Slf4j
public
class
PayNotify
Retry
Job
extends
IJobHandler
{
@Autowired
private
PayNotifyTaskMapper
pay
Transaction
NotifyTaskMapper
;
private
PayNotifyTaskMapper
payNotifyTaskMapper
;
@Autowired
private
PayNotifyServiceImpl
payNotifyService
;
@Resource
private
RocketMQTemplate
rocketMQTemplate
;
private
PayNotifyService
payNotifyService
;
@Override
@XxlJob
(
"payNotifyRetryJob"
)
public
ReturnT
<
String
>
execute
(
String
param
)
{
// 获得需要通知的任务
List
<
PayNotifyTaskDO
>
notifyTasks
=
payTransactionNotifyTaskMapper
.
selectByNotify
();
List
<
PayNotifyTaskDO
>
notifyTasks
=
payNotifyTaskMapper
.
selectListByNotify
();
// 循环任务,发送通知
for
(
PayNotifyTaskDO
notifyTask
:
notifyTasks
)
{
// 发送 MQ
payNotifyService
.
sendNotifyMessage
(
notifyTask
);
// 更新最后通知时间
// 1. 这样操作,虽然可能会出现 MQ 消费快于下面 PayTransactionNotifyTaskDO 的更新语句。但是,因为更新字段不同,所以不会有问题。
// 2. 换个视角,如果先更新 PayTransactionNotifyTaskDO ,再发送 MQ 消息。如果 MQ 消息发送失败,则 PayTransactionNotifyTaskDO 再也不会被轮询到了。
// 3. 当然,最最最完美的话,就是做事务消息,不过这样又过于复杂~
PayNotifyTaskDO
updateNotifyTask
=
new
PayNotifyTaskDO
()
.
setId
(
notifyTask
.
getId
()).
setLastExecuteTime
(
new
Date
());
payTransactionNotifyTaskMapper
.
update
(
updateNotifyTask
);
// 标记任务执行中。考虑到 MQ 可能会存在先于该操作执行完,所以更新时,增加一个 notifyTimes 作为额外条件,避免覆盖更新的问题。
PayNotifyTaskDO
updateNotifyTask
=
new
PayNotifyTaskDO
().
setId
(
notifyTask
.
getId
()).
setActive
(
true
);
payNotifyTaskMapper
.
update
(
updateNotifyTask
,
notifyTask
.
getNotifyTimes
());
}
return
new
ReturnT
<>(
"执行通知数:"
+
notifyTasks
.
size
());
}
...
...
pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/job/package-info.java
0 → 100644
浏览文件 @
efaeb5b3
package
cn
.
iocoder
.
mall
.
payservice
.
job
;
pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/consumer/AbstractPayNotifySuccessMQConsumer.java
浏览文件 @
efaeb5b3
...
...
@@ -2,6 +2,7 @@ package cn.iocoder.mall.payservice.mq.consumer;
import
cn.iocoder.common.framework.util.DateUtil
;
import
cn.iocoder.common.framework.util.ExceptionUtil
;
import
cn.iocoder.common.framework.vo.CommonResult
;
import
cn.iocoder.mall.payservice.common.dubbo.DubboReferencePool
;
import
cn.iocoder.mall.payservice.dal.mysql.dataobject.notify.PayNotifyLogDO
;
import
cn.iocoder.mall.payservice.dal.mysql.dataobject.notify.PayNotifyTaskDO
;
...
...
@@ -10,14 +11,15 @@ import cn.iocoder.mall.payservice.dal.mysql.mapper.notify.PayNotifyTaskMapper;
import
cn.iocoder.mall.payservice.enums.notify.PayNotifyStatusEnum
;
import
cn.iocoder.mall.payservice.mq.producer.message.AbstractPayNotifySuccessMessage
;
import
com.alibaba.fastjson.JSON
;
import
org.apache.rocketmq.spring.core.RocketMQListener
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.transaction.annotation.Transactional
;
import
java.util.Calendar
;
import
java.util.Date
;
import
java.util.Map
;
public
abstract
class
AbstractPayNotifySuccessMQConsumer
<
T
extends
AbstractPayNotifySuccessMessage
>
implements
RocketMQListener
<
T
>
{
public
abstract
class
AbstractPayNotifySuccessMQConsumer
<
T
extends
AbstractPayNotifySuccessMessage
>
{
// implements RocketMQListener<T> TODO 芋艿,理论来说,可以实现 RocketMQListener 接口,然后 execute 作为 onMessage 的具体实现。但是新版本貌似不行,后续在排查下;
@Autowired
private
DubboReferencePool
dubboReferencePool
;
...
...
@@ -27,21 +29,22 @@ public abstract class AbstractPayNotifySuccessMQConsumer<T extends AbstractPayNo
@Autowired
private
PayNotifyLogMapper
payTransactionNotifyLogMapper
;
@Override
@Transactional
public
void
onMessage
(
T
message
)
{
// 获得 ReferenceMeta 对象
DubboReferencePool
.
ReferenceMeta
referenceMeta
=
dubboReferencePool
.
getReferenceMeta
(
message
.
getNotifyUrl
());
public
void
execute
(
T
message
)
{
// 发起调用
String
response
=
null
;
// RPC / HTTP 调用的响应
CommonResult
<
Boolean
>
invokeResult
=
null
;
// RPC / HTTP 调用的响应
Throwable
invokeException
=
null
;
//
PayNotifyTaskDO
updateTask
=
new
PayNotifyTaskDO
()
// 更新 PayTransactionNotifyTaskDO 对象
.
setId
(
message
.
getId
())
.
setActive
(
false
)
// 标记本地通知已经完成
.
setLastExecuteTime
(
new
Date
())
.
setNotifyTimes
(
message
.
getNotifyTimes
()
+
1
);
try
{
// 获得 ReferenceMeta 对象
DubboReferencePool
.
ReferenceMeta
referenceMeta
=
dubboReferencePool
.
getReferenceMeta
(
message
.
getNotifyUrl
());
// TODO 芋艿,这里要优化下,不要在事务里,进行 RPC 调用
response
=
invoke
(
message
,
referenceMeta
);
if
(
"success"
.
equals
(
response
))
{
// 情况一,请求成功且返回成功
invokeResult
=
invoke
(
message
,
referenceMeta
);
if
(
invokeResult
.
isSuccess
(
))
{
// 情况一,请求成功且返回成功
// 更新通知成功
updateTask
.
setStatus
(
PayNotifyStatusEnum
.
SUCCESS
.
getStatus
());
payNotifyTaskMapper
.
updateById
(
updateTask
);
...
...
@@ -53,8 +56,8 @@ public abstract class AbstractPayNotifySuccessMQConsumer<T extends AbstractPayNo
payNotifyTaskMapper
.
updateById
(
updateTask
);
}
}
catch
(
Throwable
e
)
{
// 请求失败
invokeException
=
e
;
// 更新通知请求失败
response
=
ExceptionUtil
.
getRootCauseMessage
(
e
);
handleFailure
(
updateTask
,
PayNotifyStatusEnum
.
REQUEST_FAILURE
.
getStatus
());
payNotifyTaskMapper
.
updateById
(
updateTask
);
// 抛出异常,回滚事务
...
...
@@ -63,7 +66,9 @@ public abstract class AbstractPayNotifySuccessMQConsumer<T extends AbstractPayNo
}
finally
{
// 插入 PayTransactionNotifyLogDO 日志
PayNotifyLogDO
notifyLog
=
new
PayNotifyLogDO
().
setNotifyId
(
message
.
getId
())
.
setRequest
(
JSON
.
toJSONString
(
message
)).
setResponse
(
response
).
setStatus
(
updateTask
.
getStatus
());
.
setStatus
(
updateTask
.
getStatus
())
.
setRequest
(
JSON
.
toJSONString
(
message
))
.
setResponse
(
invokeResult
!=
null
?
JSON
.
toJSONString
(
invokeResult
)
:
ExceptionUtil
.
getRootCauseMessage
(
invokeException
));
payTransactionNotifyLogMapper
.
insert
(
notifyLog
);
}
}
...
...
@@ -77,8 +82,26 @@ public abstract class AbstractPayNotifySuccessMQConsumer<T extends AbstractPayNo
}
}
protected
abstract
String
invoke
(
T
message
,
DubboReferencePool
.
ReferenceMeta
referenceMeta
);
protected
abstract
CommonResult
<
Boolean
>
invoke
(
T
message
,
DubboReferencePool
.
ReferenceMeta
referenceMeta
);
protected
abstract
void
afterInvokeSuccess
(
T
message
);
/**
* 将 Dubbo 泛化调用的结果,解析成 CommonResult
*
* 目前,约定 Dubbo 返回的结果为 CommonResult<Boolean>
*
* @param dubboResult Dubbo 调用结果
* @return CommonResult 结果
*/
protected
static
CommonResult
<
Boolean
>
parseDubboGenericResult
(
Object
dubboResult
)
{
// TODO 芋艿,目前暂时这么实现,未来找下更合适的
Map
<
String
,
Object
>
dubboResultMap
=
(
Map
<
String
,
Object
>)
dubboResult
;
CommonResult
<
Boolean
>
commonResult
=
new
CommonResult
<>();
commonResult
.
setCode
((
Integer
)
dubboResultMap
.
get
(
"code"
));
commonResult
.
setMessage
((
String
)
dubboResultMap
.
get
(
"message"
));
commonResult
.
setData
((
Boolean
)
dubboResultMap
.
get
(
"data"
));
return
commonResult
;
}
}
pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/consumer/PayRefundSuccessMQConsumer.java
浏览文件 @
efaeb5b3
package
cn
.
iocoder
.
mall
.
payservice
.
mq
.
consumer
;
import
cn.iocoder.common.framework.vo.CommonResult
;
import
cn.iocoder.mall.payservice.common.dubbo.DubboReferencePool
;
import
cn.iocoder.mall.payservice.dal.mysql.dataobject.refund.PayRefundDO
;
import
cn.iocoder.mall.payservice.dal.mysql.mapper.refund.PayRefundMapper
;
...
...
@@ -25,15 +26,22 @@ public class PayRefundSuccessMQConsumer extends AbstractPayNotifySuccessMQConsum
private
PayRefundMapper
payRefundMapper
;
@Override
protected
String
invoke
(
PayRefundSuccessMessage
message
,
DubboReferencePool
.
ReferenceMeta
referenceMeta
)
{
public
void
onMessage
(
PayRefundSuccessMessage
message
)
{
super
.
execute
(
message
);
}
@Override
protected
CommonResult
<
Boolean
>
invoke
(
PayRefundSuccessMessage
message
,
DubboReferencePool
.
ReferenceMeta
referenceMeta
)
{
// 查询支付交易
PayRefundDO
refund
=
payRefundMapper
.
selectById
(
message
.
getRefundId
());
Assert
.
notNull
(
refund
,
String
.
format
(
"回调消息(%s) 退款单不能为空"
,
message
.
toString
()));
// 执行调用
GenericService
genericService
=
referenceMeta
.
getService
();
String
methodName
=
referenceMeta
.
getMethodName
();
return
(
String
)
genericService
.
$invoke
(
methodName
,
new
String
[]{
String
.
class
.
getName
(),
Integer
.
class
.
getName
()},
Object
dubboResult
=
genericService
.
$invoke
(
methodName
,
new
String
[]{
String
.
class
.
getName
(),
Integer
.
class
.
getName
()},
new
Object
[]{
message
.
getOrderId
(),
refund
.
getPrice
()});
return
parseDubboGenericResult
(
dubboResult
);
}
@Override
...
...
pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/consumer/PayTransactionSuccessMQConsumer.java
浏览文件 @
efaeb5b3
package
cn
.
iocoder
.
mall
.
payservice
.
mq
.
consumer
;
import
cn.iocoder.common.framework.vo.CommonResult
;
import
cn.iocoder.mall.payservice.common.dubbo.DubboReferencePool
;
import
cn.iocoder.mall.payservice.dal.mysql.dataobject.transaction.PayTransactionDO
;
import
cn.iocoder.mall.payservice.dal.mysql.mapper.transaction.PayTransactionMapper
;
...
...
@@ -25,15 +26,22 @@ public class PayTransactionSuccessMQConsumer extends AbstractPayNotifySuccessMQC
private
PayTransactionMapper
payTransactionMapper
;
@Override
protected
String
invoke
(
PayTransactionSuccessMessage
message
,
DubboReferencePool
.
ReferenceMeta
referenceMeta
)
{
public
void
onMessage
(
PayTransactionSuccessMessage
message
)
{
super
.
execute
(
message
);
}
@Override
protected
CommonResult
<
Boolean
>
invoke
(
PayTransactionSuccessMessage
message
,
DubboReferencePool
.
ReferenceMeta
referenceMeta
)
{
// 查询支付交易
PayTransactionDO
transaction
=
payTransactionMapper
.
selectById
(
message
.
getTransactionId
());
Assert
.
notNull
(
transaction
,
String
.
format
(
"回调消息(%s) 订单交易不能为空"
,
message
.
toString
()));
// 执行调用
GenericService
genericService
=
referenceMeta
.
getService
();
String
methodName
=
referenceMeta
.
getMethodName
();
return
(
String
)
genericService
.
$invoke
(
methodName
,
new
String
[]{
String
.
class
.
getName
(),
Integer
.
class
.
getName
()},
Object
dubboResult
=
genericService
.
$invoke
(
methodName
,
new
String
[]{
String
.
class
.
getName
(),
Integer
.
class
.
getName
()},
new
Object
[]{
message
.
getOrderId
(),
transaction
.
getPrice
()});
return
parseDubboGenericResult
(
dubboResult
);
}
@Override
...
...
pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/mq/producer/PayMQProducer.java
浏览文件 @
efaeb5b3
...
...
@@ -17,8 +17,7 @@ public class PayMQProducer {
@Autowired
private
RocketMQTemplate
template
;
public
void
sendPayRefundNotifyTaskMessage
(
PayRefundSuccessMessage
message
,
Integer
refundId
,
Integer
transactionId
,
String
orderId
)
{
message
.
setRefundId
(
refundId
).
setTransactionId
(
transactionId
).
setOrderId
(
orderId
);
public
void
sendPayRefundNotifyTaskMessage
(
PayRefundSuccessMessage
message
)
{
try
{
SendResult
sendResult
=
template
.
syncSend
(
PayTransactionSuccessMessage
.
TOPIC
,
message
);
if
(!
SendStatus
.
SEND_OK
.
equals
(
sendResult
.
getSendStatus
()))
{
...
...
@@ -29,8 +28,7 @@ public class PayMQProducer {
}
}
public
void
sendPayTransactionNotifyTaskMessage
(
PayTransactionSuccessMessage
message
,
Integer
transactionId
,
String
orderId
)
{
message
.
setTransactionId
(
transactionId
).
setOrderId
(
orderId
);
public
void
sendPayTransactionNotifyTaskMessage
(
PayTransactionSuccessMessage
message
)
{
try
{
SendResult
sendResult
=
template
.
syncSend
(
PayTransactionSuccessMessage
.
TOPIC
,
message
);
if
(!
SendStatus
.
SEND_OK
.
equals
(
sendResult
.
getSendStatus
()))
{
...
...
pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/notify/PayNotifyService.java
浏览文件 @
efaeb5b3
package
cn
.
iocoder
.
mall
.
payservice
.
service
.
notify
;
import
cn.iocoder.mall.payservice.dal.mysql.dataobject.notify.PayNotifyTaskDO
;
import
cn.iocoder.mall.payservice.dal.mysql.dataobject.refund.PayRefundDO
;
import
cn.iocoder.mall.payservice.dal.mysql.dataobject.transaction.PayTransactionDO
;
import
cn.iocoder.mall.payservice.dal.mysql.dataobject.transaction.PayTransactionExtensionDO
;
...
...
@@ -15,4 +16,7 @@ public interface PayNotifyService {
// TODO 芋艿:后续优化下,不要暴露 entity 出来
void
addPayTransactionNotifyTask
(
PayTransactionDO
transaction
,
PayTransactionExtensionDO
extension
);
// TODO 芋艿:后续优化下,不要暴露 entity 出来
void
sendNotifyMessage
(
PayNotifyTaskDO
notifyTask
);
}
pay-service-project/pay-service-app/src/main/java/cn/iocoder/mall/payservice/service/notify/impl/PayNotifyServiceImpl.java
浏览文件 @
efaeb5b3
...
...
@@ -39,8 +39,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
payNotifyTaskMapper
.
insert
(
payNotifyTaskDO
);
// 发送 MQ 消息
payMQProducer
.
sendPayRefundNotifyTaskMessage
(
PayNotifyConvert
.
INSTANCE
.
convertRefund
(
payNotifyTaskDO
),
refund
.
getId
(),
refund
.
getTransactionId
(),
refund
.
getOrderId
());
sendNotifyMessage
(
payNotifyTaskDO
);
}
@Override
...
...
@@ -54,14 +53,24 @@ public class PayNotifyServiceImpl implements PayNotifyService {
payNotifyTaskMapper
.
insert
(
payNotifyTaskDO
);
// 发送 MQ 消息
payMQProducer
.
sendPayTransactionNotifyTaskMessage
(
PayNotifyConvert
.
INSTANCE
.
convertTransaction
(
payNotifyTaskDO
),
transaction
.
getId
(),
transaction
.
getOrderId
());
sendNotifyMessage
(
payNotifyTaskDO
);
}
@Override
public
void
sendNotifyMessage
(
PayNotifyTaskDO
notifyTask
)
{
if
(
PayNotifyType
.
TRANSACTION
.
getType
().
equals
(
notifyTask
.
getType
()))
{
payMQProducer
.
sendPayTransactionNotifyTaskMessage
(
PayNotifyConvert
.
INSTANCE
.
convertTransaction
(
notifyTask
));
}
else
if
(
PayNotifyType
.
REFUND
.
getType
().
equals
(
notifyTask
.
getType
()))
{
payMQProducer
.
sendPayRefundNotifyTaskMessage
(
PayNotifyConvert
.
INSTANCE
.
convertRefund
(
notifyTask
));
}
else
{
throw
new
IllegalArgumentException
(
String
.
format
(
"通知任务(%s) 无法发送通知消息"
,
notifyTask
.
toString
()));
}
}
private
PayNotifyTaskDO
createBasePayNotifyTaskDO
(
String
appId
,
String
notifyUrl
)
{
return
new
PayNotifyTaskDO
()
.
setAppId
(
appId
)
.
setStatus
(
PayNotifyStatusEnum
.
WAITING
.
getStatus
())
.
setStatus
(
PayNotifyStatusEnum
.
WAITING
.
getStatus
())
.
setActive
(
true
)
.
setNotifyTimes
(
0
).
setMaxNotifyTimes
(
PayNotifyTaskDO
.
NOTIFY_FREQUENCY
.
length
+
1
)
.
setNextNotifyTime
(
DateUtil
.
addDate
(
Calendar
.
SECOND
,
PayNotifyTaskDO
.
NOTIFY_FREQUENCY
[
0
]))
.
setNotifyUrl
(
notifyUrl
);
...
...
pay-service-project/pay-service-app/src/main/resources/application-dev.yaml
浏览文件 @
efaeb5b3
spring
:
# 数据源配置项
datasource
:
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_pay?useSSL=false&useUnicode=true&characterEncoding=UTF-8
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_pay?useSSL=false&useUnicode=true&characterEncoding=UTF-8
&serverTimezone=CTT
driver-class-name
:
com.mysql.jdbc.Driver
username
:
root
password
:
3WLiVUBEwTbvAfsh
...
...
@@ -19,3 +19,13 @@ dubbo:
registry
:
# address: spring-cloud://400-infra.server.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址
address
:
nacos://400-infra.server.iocoder.cn:8848?namespace=dev
# 指定 Dubbo 服务注册中心的地址
# XXL-Job 配置项
xxl
:
job
:
admin
:
addresses
:
http://127.0.0.1:9099/
executor
:
appname
:
${spring.application.name}
logpath
:
/data/applogs/xxl-job/
accessToken
:
pay-service-project/pay-service-app/src/main/resources/application-local.yaml
浏览文件 @
efaeb5b3
spring
:
# 数据源配置项
datasource
:
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_pay?useSSL=false&useUnicode=true&characterEncoding=UTF-8
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_pay?useSSL=false&useUnicode=true&characterEncoding=UTF-8
&serverTimezone=CTT
driver-class-name
:
com.mysql.jdbc.Driver
username
:
root
password
:
3WLiVUBEwTbvAfsh
...
...
@@ -22,3 +22,19 @@ dubbo:
# Dubbo 服务提供者的配置
provider
:
tag
:
${DUBBO_TAG}
# Dubbo 路由分组
# XXL-Job 配置项
xxl
:
job
:
enabled
:
false
# 本地开发时,关闭 XXL-Job
admin
:
addresses
:
http://400-infra.server.iocoder.cn:9099
executor
:
appname
:
${spring.application.name}
accessToken
:
# MyBatis Plus 配置
mybatis-plus
:
configuration
:
log-impl
:
org.apache.ibatis.logging.stdout.StdOutImpl
# 本地开发环境下,多打印 SQL 到控制台
moved/pay/pay-application/src/test/java
/DubboGenericInvokerTest.java
→
pay-service-project/pay-service-integration-test/src/test/java/cn/iocoder/mall/payservice/common/dubbo
/DubboGenericInvokerTest.java
浏览文件 @
efaeb5b3
package
cn
.
iocoder
.
mall
.
payservice
.
common
.
dubbo
;
import
cn.iocoder.common.framework.vo.CommonResult
;
import
org.apache.dubbo.config.ApplicationConfig
;
import
org.apache.dubbo.config.ReferenceConfig
;
import
org.apache.dubbo.config.RegistryConfig
;
import
org.apache.dubbo.rpc.service.GenericService
;
import
java.util.Map
;
public
class
DubboGenericInvokerTest
{
public
static
void
main
(
String
[]
args
)
{
...
...
@@ -10,13 +15,14 @@ public class DubboGenericInvokerTest {
application
.
setName
(
"api-generic-consumer"
);
RegistryConfig
registry
=
new
RegistryConfig
();
registry
.
setAddress
(
"
zookeeper://127.0.0.1:2181
"
);
registry
.
setAddress
(
"
nacos://400-infra.server.iocoder.cn:8848?namespace=dev
"
);
application
.
setRegistry
(
registry
);
ReferenceConfig
<
GenericService
>
reference
=
new
ReferenceConfig
<>();
// 弱类型接口名
reference
.
setInterface
(
"cn.iocoder.mall.order.api.OrderService"
);
reference
.
setInterface
(
"cn.iocoder.mall.tradeservice.rpc.order.TradeOrderRpc"
);
reference
.
setVersion
(
"1.0.0"
);
// 声明为泛化接口
reference
.
setGeneric
(
true
);
...
...
@@ -25,8 +31,19 @@ public class DubboGenericInvokerTest {
// 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用
GenericService
genericService
=
reference
.
get
();
String
name
=
(
String
)
genericService
.
$invoke
(
"updatePaySuccess"
,
new
String
[]{
String
.
class
.
getName
()},
new
Object
[]{
"1"
});
System
.
out
.
println
(
name
);
Object
result
=
genericService
.
$invoke
(
"updateTradeOrderPaySuccess"
,
new
String
[]{
String
.
class
.
getName
(),
Integer
.
class
.
getName
()},
new
Object
[]{
"1"
,
100
});
CommonResult
<
Boolean
>
commonResult
=
parseCommonResult
((
Map
<
String
,
Object
>)
result
);
System
.
out
.
println
(
result
);
}
private
static
CommonResult
<
Boolean
>
parseCommonResult
(
Map
<
String
,
Object
>
dubboResult
)
{
CommonResult
<
Boolean
>
commonResult
=
new
CommonResult
<>();
commonResult
.
setCode
((
Integer
)
dubboResult
.
get
(
"code"
));
commonResult
.
setMessage
((
String
)
dubboResult
.
get
(
"message"
));
commonResult
.
setData
((
Boolean
)
dubboResult
.
get
(
"data"
));
return
commonResult
;
}
}
pay-service-project/pay-service-integration-test/src/test/java/cn/iocoder/mall/payservice/common/package-info.java
0 → 100644
浏览文件 @
efaeb5b3
package
cn
.
iocoder
.
mall
.
payservice
.
common
;
product-service-project/product-service-app/src/main/resources/application-dev.yaml
浏览文件 @
efaeb5b3
spring
:
# 数据源配置项
datasource
:
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_product?useSSL=false&useUnicode=true&characterEncoding=UTF-8
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_product?useSSL=false&useUnicode=true&characterEncoding=UTF-8
&serverTimezone=CTT
driver-class-name
:
com.mysql.jdbc.Driver
username
:
root
password
:
3WLiVUBEwTbvAfsh
...
...
product-service-project/product-service-app/src/main/resources/application-local.yaml
浏览文件 @
efaeb5b3
spring
:
# 数据源配置项
datasource
:
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_product?useSSL=false&useUnicode=true&characterEncoding=UTF-8
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_product?useSSL=false&useUnicode=true&characterEncoding=UTF-8
&serverTimezone=CTT
driver-class-name
:
com.mysql.jdbc.Driver
username
:
root
password
:
3WLiVUBEwTbvAfsh
...
...
promotion-service-project/promotion-service-app/src/main/resources/application-dev.yaml
浏览文件 @
efaeb5b3
spring
:
# 数据源配置项
datasource
:
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_promotion?useSSL=false&useUnicode=true&characterEncoding=UTF-8
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_promotion?useSSL=false&useUnicode=true&characterEncoding=UTF-8
&serverTimezone=CTT
driver-class-name
:
com.mysql.jdbc.Driver
username
:
root
password
:
3WLiVUBEwTbvAfsh
...
...
promotion-service-project/promotion-service-app/src/main/resources/application-local.yaml
浏览文件 @
efaeb5b3
spring
:
# 数据源配置项
datasource
:
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_promotion?useSSL=false&useUnicode=true&characterEncoding=UTF-8
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_promotion?useSSL=false&useUnicode=true&characterEncoding=UTF-8
&serverTimezone=CTT
driver-class-name
:
com.mysql.jdbc.Driver
username
:
root
password
:
3WLiVUBEwTbvAfsh
...
...
system-service-project/system-service-app/src/main/resources/application-dev.yaml
浏览文件 @
efaeb5b3
spring
:
# 数据源配置项
datasource
:
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_system?useSSL=false&useUnicode=true&characterEncoding=UTF-8
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_system?useSSL=false&useUnicode=true&characterEncoding=UTF-8
&serverTimezone=CTT
driver-class-name
:
com.mysql.jdbc.Driver
username
:
root
password
:
3WLiVUBEwTbvAfsh
...
...
system-service-project/system-service-app/src/main/resources/application-local.yaml
浏览文件 @
efaeb5b3
spring
:
# 数据源配置项
datasource
:
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_system?useSSL=false&useUnicode=true&characterEncoding=UTF-8
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_system?useSSL=false&useUnicode=true&characterEncoding=UTF-8
&serverTimezone=CTT
driver-class-name
:
com.mysql.jdbc.Driver
username
:
root
password
:
3WLiVUBEwTbvAfsh
...
...
trade-service-project/trade-service-api/src/main/java/cn/iocoder/mall/tradeservice/rpc/order/TradeOrderRpc.java
浏览文件 @
efaeb5b3
...
...
@@ -38,6 +38,17 @@ public interface TradeOrderRpc {
*/
CommonResult
<
PageResult
<
TradeOrderRespDTO
>>
pageTradeOrder
(
TradeOrderPageReqDTO
pageDTO
);
// TODO 芋艿:需要重构成入参是 DTO,方便后续升级;返回是 CommonResult,用于返回失败的原因
/**
* 更新交易订单支付成功
*
* 目前用于对接 pay-service 支付服务,回调该交易订单在三方支付平台,支付成功
*
* @param tradeOrderId 交易订单编号
* @param payAmount 支付金额
* @return 成功
*/
CommonResult
<
Boolean
>
updateTradeOrderPaySuccess
(
String
tradeOrderId
,
Integer
payAmount
);
}
trade-service-project/trade-service-app/src/main/java/cn/iocoder/mall/tradeservice/dal/mysql/mapper/order/TradeOrderItemMapper.java
浏览文件 @
efaeb5b3
...
...
@@ -20,4 +20,9 @@ public interface TradeOrderItemMapper extends BaseMapper<TradeOrderItemDO> {
return
selectList
(
new
QueryWrapper
<
TradeOrderItemDO
>().
in
(
"order_id"
,
orderIds
));
}
default
int
updateListByOrderId
(
TradeOrderItemDO
update
,
Integer
orderId
,
Integer
whereStatus
)
{
return
update
(
update
,
new
QueryWrapper
<
TradeOrderItemDO
>().
eq
(
"order_id"
,
orderId
)
.
eq
(
"status"
,
whereStatus
));
}
}
trade-service-project/trade-service-app/src/main/java/cn/iocoder/mall/tradeservice/dal/mysql/mapper/order/TradeOrderMapper.java
浏览文件 @
efaeb5b3
...
...
@@ -4,6 +4,7 @@ import cn.iocoder.mall.mybatis.core.query.QueryWrapperX;
import
cn.iocoder.mall.mybatis.core.util.PageUtil
;
import
cn.iocoder.mall.tradeservice.dal.mysql.dataobject.order.TradeOrderDO
;
import
cn.iocoder.mall.tradeservice.rpc.order.dto.TradeOrderPageReqDTO
;
import
com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.baomidou.mybatisplus.core.metadata.IPage
;
import
org.springframework.stereotype.Repository
;
...
...
@@ -17,4 +18,9 @@ public interface TradeOrderMapper extends BaseMapper<TradeOrderDO> {
.
eqIfPresent
(
"status"
,
pageReqDTO
.
getOrderStatus
()));
}
default
int
update
(
TradeOrderDO
update
,
Integer
whereOrderStatus
)
{
return
update
(
update
,
new
QueryWrapper
<
TradeOrderDO
>()
.
eq
(
"id"
,
update
.
getId
()).
eq
(
"order_status"
,
whereOrderStatus
));
}
}
trade-service-project/trade-service-app/src/main/java/cn/iocoder/mall/tradeservice/rpc/order/TradeOrderRpcImpl.java
浏览文件 @
efaeb5b3
...
...
@@ -37,4 +37,10 @@ public class TradeOrderRpcImpl implements TradeOrderRpc {
return
success
(
tradeOrderService
.
pageTradeOrder
(
pageDTO
));
}
@Override
public
CommonResult
<
Boolean
>
updateTradeOrderPaySuccess
(
String
tradeOrderId
,
Integer
payAmount
)
{
tradeOrderService
.
updateTradeOrderPaySuccess
(
Integer
.
valueOf
(
tradeOrderId
),
payAmount
);
return
success
(
true
);
}
}
trade-service-project/trade-service-app/src/main/java/cn/iocoder/mall/tradeservice/service/order/TradeOrderService.java
浏览文件 @
efaeb5b3
...
...
@@ -37,4 +37,12 @@ public interface TradeOrderService {
*/
PageResult
<
TradeOrderRespDTO
>
pageTradeOrder
(
TradeOrderPageReqDTO
pageReqDTO
);
/**
* 更新交易订单支付成功
*
* @param tradeOrderId 交易订单编号
* @param payAmount 支付金额
*/
void
updateTradeOrderPaySuccess
(
Integer
tradeOrderId
,
Integer
payAmount
);
}
trade-service-project/trade-service-app/src/main/java/cn/iocoder/mall/tradeservice/service/order/impl/TradeOrderServiceImpl.java
浏览文件 @
efaeb5b3
...
...
@@ -39,7 +39,7 @@ import java.util.*;
import
java.util.stream.Collectors
;
import
static
cn
.
iocoder
.
common
.
framework
.
util
.
CollectionUtils
.
convertSet
;
import
static
cn
.
iocoder
.
mall
.
tradeservice
.
enums
.
OrderErrorCodeConstants
.
ORDER_GET_GOODS_INFO_INCORRECT
;
import
static
cn
.
iocoder
.
mall
.
tradeservice
.
enums
.
OrderErrorCodeConstants
.
*
;
import
static
cn
.
iocoder
.
mall
.
userservice
.
enums
.
UserErrorCodeConstants
.
USER_ADDRESS_NOT_FOUND
;
/**
...
...
@@ -240,4 +240,40 @@ public class TradeOrderServiceImpl implements TradeOrderService {
return
pageResult
;
}
@Override
@Transactional
public
void
updateTradeOrderPaySuccess
(
Integer
tradeOrderId
,
Integer
payAmount
)
{
// if (true) {
// throw new IllegalArgumentException("测试失败的情况");
// }
// 校验交易订单,是否可以
TradeOrderDO
tradeOrderDO
=
tradeOrderMapper
.
selectById
(
tradeOrderId
);
if
(
tradeOrderDO
==
null
)
{
// 订单不存在
throw
ServiceExceptionUtil
.
exception
(
ORDER_NOT_EXISTENT
);
}
if
(!
tradeOrderDO
.
getOrderStatus
().
equals
(
TradeOrderStatusEnum
.
WAITING_PAYMENT
.
getValue
()))
{
// 状态不处于等待支付
throw
ServiceExceptionUtil
.
exception
(
ORDER_STATUS_NOT_WAITING_PAYMENT
);
}
if
(!
tradeOrderDO
.
getPresentPrice
().
equals
(
payAmount
))
{
// 支付金额不正确
throw
ServiceExceptionUtil
.
exception
(
ORDER_PAY_AMOUNT_ERROR
);
}
// 更新 TradeOrderDO 状态为已支付,等待发货
TradeOrderDO
updateOrderObj
=
new
TradeOrderDO
().
setId
(
tradeOrderId
)
.
setOrderStatus
(
TradeOrderStatusEnum
.
WAIT_SHIPMENT
.
getValue
())
.
setPayPrice
(
payAmount
)
.
setPayTime
(
new
Date
());
int
updateCount
=
tradeOrderMapper
.
update
(
updateOrderObj
,
TradeOrderStatusEnum
.
WAITING_PAYMENT
.
getValue
());
if
(
updateCount
<=
0
)
{
throw
ServiceExceptionUtil
.
exception
(
ORDER_STATUS_NOT_WAITING_PAYMENT
);
}
// 更新 TradeOrderItemDO 状态为已支付,等待发货
TradeOrderItemDO
updateOrderItemObj
=
new
TradeOrderItemDO
()
.
setStatus
(
TradeOrderStatusEnum
.
WAIT_SHIPMENT
.
getValue
());
tradeOrderItemMapper
.
updateListByOrderId
(
updateOrderItemObj
,
tradeOrderId
,
TradeOrderStatusEnum
.
WAITING_PAYMENT
.
getValue
());
}
}
trade-service-project/trade-service-app/src/main/resources/application-dev.yaml
浏览文件 @
efaeb5b3
spring
:
# 数据源配置项
datasource
:
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_trade?useSSL=false&useUnicode=true&characterEncoding=UTF-8
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_trade?useSSL=false&useUnicode=true&characterEncoding=UTF-8
&serverTimezone=CTT
driver-class-name
:
com.mysql.jdbc.Driver
username
:
root
password
:
3WLiVUBEwTbvAfsh
...
...
trade-service-project/trade-service-app/src/main/resources/application-local.yaml
浏览文件 @
efaeb5b3
spring
:
# 数据源配置项
datasource
:
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_trade?useSSL=false&useUnicode=true&characterEncoding=UTF-8
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_trade?useSSL=false&useUnicode=true&characterEncoding=UTF-8
&serverTimezone=CTT
driver-class-name
:
com.mysql.jdbc.Driver
username
:
root
password
:
3WLiVUBEwTbvAfsh
...
...
@@ -25,3 +25,8 @@ dubbo:
# Dubbo 服务提供者的配置
provider
:
tag
:
${DUBBO_TAG}
# Dubbo 路由分组
# MyBatis Plus 配置
mybatis-plus
:
configuration
:
log-impl
:
org.apache.ibatis.logging.stdout.StdOutImpl
# 本地开发环境下,多打印 SQL 到控制台
user-service-project/user-service-app/src/main/resources/application-dev.yaml
浏览文件 @
efaeb5b3
spring
:
# 数据源配置项
datasource
:
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_user?useSSL=false&useUnicode=true&characterEncoding=UTF-8
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_user?useSSL=false&useUnicode=true&characterEncoding=UTF-8
&serverTimezone=CTT
driver-class-name
:
com.mysql.jdbc.Driver
username
:
root
password
:
3WLiVUBEwTbvAfsh
...
...
user-service-project/user-service-app/src/main/resources/application-local.yaml
浏览文件 @
efaeb5b3
spring
:
# 数据源配置项
datasource
:
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_user?useSSL=false&useUnicode=true&characterEncoding=UTF-8
url
:
jdbc:mysql://400-infra.server.iocoder.cn:3306/mall_user?useSSL=false&useUnicode=true&characterEncoding=UTF-8
&serverTimezone=CTT
driver-class-name
:
com.mysql.jdbc.Driver
username
:
root
password
:
3WLiVUBEwTbvAfsh
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论