开发者学堂课程【RocketMQ 知识精讲与项目实战(第二阶段):支付回调代码实现】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/703/detail/12437
支付回调代码实现
1、根据分析的流程进行代码的实现
//创建接口传递参数,将来 callbackpayment 方法是被第三方平台所调用的,它回调接口时通常会提交参数,最重要的是当前它包含支付业务的编号,当前用户支付的状态,封装成 TradePay
tradePay
package com. itheima .api ;
import com. itheima . entity. Result ;
import com. itheima. shop. pojo. TradePay;
public interface IPayService {
public Result createPayment(TradePay tradePay) ;
Public
Result callbackP
a
yment(TradePay tradePay);
2、根据流程把注释进行完善
接收到回调的请求后
log.info("支付回调");
//1
.判断用户支付状态
if(tradePay.getIsPaid().intValue( )==ShopCode. SHOP_ ORDER_ PAY_ STATUS_ IS_ PAY. getCode(). intValue(
)
如果状态等于已经支付的状态,就要做一系列的处理,如果不等于已经支付的状态,直接抛异常即可。
//2.更新支付订单状态为已支付
查询 payid,根据支付 id 查到当前 pay 的对象
Long payId = tradePay. getPay
i
d();
当用户支付成功后,会回调回来,回调到方法上,支付成功后获得当前支付订单的 id
TradePaypay=
tradePayMapper .selectByPrimaryKey(pay
i
d);
把支付订单查询出来
如果它等于空,抛异常
//判断支付订单是否存在
if(pay==null){
CastException.cast(ShopCode.SHOP_PAYMENT_NOT_ FOUND);
}
如果订单存在
pay. setIsPaid(ShopCode . SHOP_ ORDER_ PAY_ STATUS_ IS_ PAY. getCode());
将状态设置为已支付,更新回去
在数据库中更新
Int
r
=tradePayMapper.
updateByPrimaryKeySelectiv
e
(pay) ;
更新完获得结果,如果等于1,更新成功,发送消息到 mq,让其他系统接收到当前支付成功的状态,进行其他的处理,创建支付成功的消息,把对象创建出来,存到数据库的 trade_mq_producer_temp 表,表里面有 id,group_name,key,body 等信息,把这些信息在对象中进行封装。
Log. info("订单支付
状态改为已支付
");
if(r==1){
//3.创建支付成功的信息
创建对象
TradeMqProducerTemp tradeMqProducerTemp = new
TradeMqProducerTemp();
更新成功后创建消息的对象,发送消息之前,为保证消息一定要发送成功,将消息持久化到数据库
id 的产生是通过字符串类型,用 String.valuOf 进行转换。
tradeMqProducerTemp. setId( String.valueOf( idWorker. nextId( ))) ;
3、完成属性的注入
@Value("${rocketmq . producer . group}")
private String groupName ;
@Value("${mq .topic}")
private String topic;
@Value( "${mq.pay.tag}")
private String tag;
4、封装数据,为了避免应用编码,可以把它配置到配置文件中,继续封装。
//3.创建支付成功的消息
TradeMqProducerTemp tradeMqProducerTemp = new
TradeMqProducerTemp();
tradeMqProducerTemp. setId(String. valueOf( idWorker.
nextId()));
tradeMqProducerTemp . setGroupName (groupName);
tradeMqProducerTemp. setMsgTopic(topic);
tradeMqProducerTemp. setMsgTag(tag);
判断如果当前是发送成功的状态,就将上一步持久化数据库的消息删除掉,如果没有发送成功,消息会保留到数据库里面,可以做一些其他的处理,比如写一个定时任务,定时的扫描未发送成功的消息,进行发送的处理。
在这个过程中可以加上一些日志输出,方便查看。
@Slf4j
业务标识的key,以当前支付订单的id作为业务标识的 key 比较好,因为当前的支付订单已经完成支付,将来也好去数据库中查询出来支付订单的数据,它需要字符串,所以进行转换。
tradeMqProducerTemp. setMsgKey(String.
valueOf(tradePay. getPayId()));
转换成字符串
tradeMqProducerTemp.setMsgBody(JSON.toISONString(tradePay));
设置当前的创建时间
tradeMqProducerTemp. setCreateTime(new Date());
要发送消息的内容都已经创建好
5、借助 mapper,从资料中找到
TradeMqProducerTempMapper.java 拿过来。
把对应的 resources 映射文件
TradeMqProducerTempMapper.xml 拿过来。
添加注解,不报错。
@mapper
6、@Autowired
privateTradeMqProducerTempMapper
mgProducerTImpMapper;
//4.为了消息能100%的发送到 MQ 中,将消息持久化数据库
mqProducerTempMapper . insert(tradeMqProducerTemp);
log. info("将支付成功消息持久化到数据库");
//5.发送消息到 MQ,封装方法
sendMessage (topic, t
a
g, String. valueOf(tradePay.
getPayId()), JSON. toJSONString(tradePay));
接收结果
if( result. getSendStatus() . equals (SendStatus .SEND_ OK))
{
}
打印日志
Log . info("消息发送成功");
//6.等待发送结果,如果MQ接受到消息,删除发送成功的消息
mqProducerTempMapper.deleteByPrimaryKey( tradeMqProducerTemp . getId());
Log. info("持久化到数据库的消息删除");
这样在测试时就可以看到日志的输出
通过 mapper 插入到数据库,通过主键找到删掉,这样就可以把已经发送的消息进行删除。
如果是已经支付的状态,抛出异常。
}
}
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) {
使用字符串归类进行判断
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 message = new Message(topic, tag, key, body.
getBytes());
SendResult sendResult=rocketMQTemplate.
getProducer( ). send(message);
发送完成后
,
返回发送的结果
return sendResult;
根据这个结果判断目前持久化的消息是否从数据库中删掉
7、拿到模版类发送
@Autowired
private RocketMQT emplate rockatMQTemplate;