当前位置: 首页 > news >正文

河东天津网站建设闵行做网站

河东天津网站建设,闵行做网站,蝉知cms wordpress,cms支持是什么1. 案例介绍 1.1 业务分析 模拟电商网站购物场景中的【下单】和【支付】业务 ###1#xff09;下单 用户请求订单系统下单订单系统通过RPC调用订单服务下单订单服务调用优惠券服务#xff0c;扣减优惠券订单服务调用调用库存服务#xff0c;校验并扣减库存订单服务调用用户…1. 案例介绍 1.1 业务分析 模拟电商网站购物场景中的【下单】和【支付】业务 ###1下单 用户请求订单系统下单订单系统通过RPC调用订单服务下单订单服务调用优惠券服务扣减优惠券订单服务调用调用库存服务校验并扣减库存订单服务调用用户服务扣减用户余额订单服务完成确认订单 ###2支付 用户请求支付系统支付系统调用第三方支付平台API进行发起支付流程用户通过第三方支付平台支付成功后第三方支付平台回调通知支付系统支付系统调用订单服务修改订单状态支付系统调用积分服务添加积分支付系统调用日志服务记录日志 1.2 问题分析 问题1 用户提交订单后扣减库存成功、扣减优惠券成功、使用余额成功但是在确认订单操作失败需要对库存、库存、余额进行回退。 如何保证数据的完整性 使用MQ保证在下单失败后系统数据的完整性 ###问题2 用户通过第三方支付平台支付宝、微信支付成功后第三方支付平台要通过回调API异步通知商家支付系统用户支付结果支付系统根据支付结果修改订单状态、记录支付日志和给用户增加积分。 商家支付系统如何保证在收到第三方支付平台的异步通知时如何快速给第三方支付凭条做出回应 通过MQ进行数据分发提高系统处理性能 2. 技术分析 2.1 技术选型 SpringBootDubboZookeeperRocketMQMysql 2.2 SpringBoot整合RocketMQ 下载rocketmq-spring项目 将rocketmq-spring安装到本地仓库 mvn install -Dmaven.skip.testtrue2.2.1 消息生产者 1添加依赖 parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.0.1.RELEASE/version /parentpropertiesrocketmq-spring-boot-starter-version2.0.3/rocketmq-spring-boot-starter-version /propertiesdependenciesdependencygroupIdorg.apache.rocketmq/groupIdartifactIdrocketmq-spring-boot-starter/artifactIdversion${rocketmq-spring-boot-starter-version}/version/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.6/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependencies2配置文件 # application.properties rocketmq.name-server192.168.25.135:9876;192.168.25.138:9876 rocketmq.producer.groupmy-group3启动类 SpringBootApplication public class MQProducerApplication {public static void main(String[] args) {SpringApplication.run(MQSpringBootApplication.class);} }4测试类 RunWith(SpringRunner.class) SpringBootTest(classes {MQSpringBootApplication.class}) public class ProducerTest {Autowiredprivate RocketMQTemplate rocketMQTemplate;Testpublic void test1(){rocketMQTemplate.convertAndSend(springboot-mq,hello springboot rocketmq);} }2.2.2 消息消费者 1添加依赖 同消息生产者 2配置文件 同消息生产者 3启动类 SpringBootApplication public class MQConsumerApplication {public static void main(String[] args) {SpringApplication.run(MQSpringBootApplication.class);} }4消息监听器 Slf4j Component RocketMQMessageListener(topic springboot-mq,consumerGroup springboot-mq-consumer-1) public class Consumer implements RocketMQListenerString {Overridepublic void onMessage(String message) {log.info(Receive messagemessage);} }2.3 SpringBoot整合Dubbo 下载dubbo-spring-boot-starter依赖包 将dubbo-spring-boot-starter安装到本地仓库 mvn install -Dmaven.skip.testtrue2.3.1 搭建Zookeeper集群 1准备工作 安装JDK将Zookeeper上传到服务器解压Zookeeper并创建data目录将conf下的zoo_sample.cfg文件改名为zoo.cfg建立/user/local/zookeeper-cluster,将解压后的Zookeeper复制到以下三个目录 /usr/local/zookeeper-cluster/zookeeper-1 /usr/local/zookeeper-cluster/zookeeper-2 /usr/local/zookeeper-cluster/zookeeper-3配置每一个 Zookeeper 的 dataDirzoo.cfg clientPort 分别为 2181 2182 2183 修改/usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfg clientPort2181 dataDir/usr/local/zookeeper-cluster/zookeeper-1/data​ 修改/usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfg clientPort2182 dataDir/usr/local/zookeeper-cluster/zookeeper-2/data​ 修改/usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfg clientPort2183 dataDir/usr/local/zookeeper-cluster/zookeeper-3/data2配置集群 在每个 zookeeper 的 data 目录下创建一个 myid 文件内容分别是 1、2、3 。这个文件就是记录每个服务器的 ID 在每一个 zookeeper 的 zoo.cfg 配置客户端访问端口clientPort和集群服务器 IP 列表。 集群服务器 IP 列表如下 server.1192.168.25.140:2881:3881 server.2192.168.25.140:2882:3882 server.3192.168.25.140:2883:3883解释server.服务器 ID服务器 IP 地址服务器之间通信端口服务器之间投票选举端口 3启动集群 启动集群就是分别启动每个实例。 2.3.2 RPC服务接口 public interface IUserService {public String sayHello(String name); }2.3.3 服务提供者 1添加依赖 parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.0.1.RELEASE/version /parentdependencies!--dubbo--dependencygroupIdcom.alibaba.spring.boot/groupIdartifactIddubbo-spring-boot-starter/artifactIdversion2.0.0/version/dependency!--spring-boot-stater--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactIdexclusionsexclusionartifactIdlog4j-to-slf4j/artifactIdgroupIdorg.apache.logging.log4j/groupId/exclusion/exclusions/dependency!--zookeeper--dependencygroupIdorg.apache.zookeeper/groupIdartifactIdzookeeper/artifactIdversion3.4.10/versionexclusionsexclusiongroupIdorg.slf4j/groupIdartifactIdslf4j-log4j12/artifactId/exclusionexclusiongroupIdlog4j/groupIdartifactIdlog4j/artifactId/exclusion/exclusions/dependencydependencygroupIdcom.101tec/groupIdartifactIdzkclient/artifactIdversion0.9/versionexclusionsexclusionartifactIdslf4j-log4j12/artifactIdgroupIdorg.slf4j/groupId/exclusion/exclusions/dependency!--API--dependencygroupIdcom.itheima.demo/groupIdartifactIddubbo-api/artifactIdversion1.0-SNAPSHOT/version/dependency/dependencies2配置文件 # application.properties spring.application.namedubbo-demo-provider spring.dubbo.application.iddubbo-demo-provider spring.dubbo.application.namedubbo-demo-provider spring.dubbo.registry.addresszookeeper://192.168.25.140:2181;zookeeper://192.168.25.140:2182;zookeeper://192.168.25.140:2183 spring.dubbo.servertrue spring.dubbo.protocol.namedubbo spring.dubbo.protocol.port208803启动类 EnableDubboConfiguration SpringBootApplication public class ProviderBootstrap {public static void main(String[] args) throws IOException {SpringApplication.run(ProviderBootstrap.class,args);}}4服务实现 Component Service(interfaceClass IUserService.class) public class UserServiceImpl implements IUserService{Overridepublic String sayHello(String name) {return hello:name;} }2.3.4 服务消费者 1添加依赖 parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.0.1.RELEASE/version/parentdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!--dubbo--dependencygroupIdcom.alibaba.spring.boot/groupIdartifactIddubbo-spring-boot-starter/artifactIdversion2.0.0/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactIdexclusionsexclusionartifactIdlog4j-to-slf4j/artifactIdgroupIdorg.apache.logging.log4j/groupId/exclusion/exclusions/dependency!--zookeeper--dependencygroupIdorg.apache.zookeeper/groupIdartifactIdzookeeper/artifactIdversion3.4.10/versionexclusionsexclusiongroupIdorg.slf4j/groupIdartifactIdslf4j-log4j12/artifactId/exclusionexclusiongroupIdlog4j/groupIdartifactIdlog4j/artifactId/exclusion/exclusions/dependencydependencygroupIdcom.101tec/groupIdartifactIdzkclient/artifactIdversion0.9/versionexclusionsexclusionartifactIdslf4j-log4j12/artifactIdgroupIdorg.slf4j/groupId/exclusion/exclusions/dependency!--API--dependencygroupIdcom.itheima.demo/groupIdartifactIddubbo-api/artifactIdversion1.0-SNAPSHOT/version/dependency/dependencies2配置文件 # application.properties spring.application.namedubbo-demo-consumer spring.dubbo.application.namedubbo-demo-consumer spring.dubbo.application.iddubbo-demo-consumerspring.dubbo.registry.addresszookeeper://192.168.25.140:2181;zookeeper://192.168.25.140:2182;zookeeper://192.168.25.140:21833启动类 EnableDubboConfiguration SpringBootApplication public class ConsumerBootstrap {public static void main(String[] args) {SpringApplication.run(ConsumerBootstrap.class);} }4Controller RestController RequestMapping(/user) public class UserController {Referenceprivate IUserService userService;RequestMapping(/sayHello)public String sayHello(String name){return userService.sayHello(name);}}3. 环境搭建 3.1 数据库 1优惠券表 FieldTypeCommentcoupon_idbigint(50) NOT NULL优惠券IDcoupon_pricedecimal(10,2) NULL优惠券金额user_idbigint(50) NULL用户IDorder_idbigint(32) NULL订单IDis_usedint(1) NULL是否使用 0未使用 1已使用used_timetimestamp NULL使用时间 2商品表 FieldTypeCommentgoods_idbigint(50) NOT NULL主键goods_namevarchar(255) NULL商品名称goods_numberint(11) NULL商品库存goods_pricedecimal(10,2) NULL商品价格goods_descvarchar(255) NULL商品描述add_timetimestamp NULL添加时间 3订单表 FieldTypeCommentorder_idbigint(50) NOT NULL订单IDuser_idbigint(50) NULL用户IDorder_statusint(1) NULL订单状态 0未确认 1已确认 2已取消 3无效 4退款pay_statusint(1) NULL支付状态 0未支付 1支付中 2已支付shipping_statusint(1) NULL发货状态 0未发货 1已发货 2已退货addressvarchar(255) NULL收货地址consigneevarchar(255) NULL收货人goods_idbigint(50) NULL商品IDgoods_numberint(11) NULL商品数量goods_pricedecimal(10,2) NULL商品价格goods_amountdecimal(10,0) NULL商品总价shipping_feedecimal(10,2) NULL运费order_amountdecimal(10,2) NULL订单价格coupon_idbigint(50) NULL优惠券IDcoupon_paiddecimal(10,2) NULL优惠券money_paiddecimal(10,2) NULL已付金额pay_amountdecimal(10,2) NULL支付金额add_timetimestamp NULL创建时间confirm_timetimestamp NULL订单确认时间pay_timetimestamp NULL支付时间 4订单商品日志表 FieldTypeCommentgoods_idint(11) NOT NULL商品IDorder_idvarchar(32) NOT NULL订单IDgoods_numberint(11) NULL库存数量log_timedatetime NULL记录时间 5用户表 FieldTypeCommentuser_idbigint(50) NOT NULL用户IDuser_namevarchar(255) NULL用户姓名user_passwordvarchar(255) NULL用户密码user_mobilevarchar(255) NULL手机号user_scoreint(11) NULL积分user_reg_timetimestamp NULL注册时间user_moneydecimal(10,0) NULL用户余额 6用户余额日志表 FieldTypeCommentuser_idbigint(50) NOT NULL用户IDorder_idbigint(50) NOT NULL订单IDmoney_log_typeint(1) NOT NULL日志类型 1订单付款 2 订单退款use_moneydecimal(10,2) NULL操作金额create_timetimestamp NULL日志时间 7订单支付表 FieldTypeCommentpay_idbigint(50) NOT NULL支付编号order_idbigint(50) NULL订单编号pay_amountdecimal(10,2) NULL支付金额is_paidint(1) NULL是否已支付 1否 2是 8MQ消息生产表 FieldTypeCommentidvarchar(100) NOT NULL主键group_namevarchar(100) NULL生产者组名msg_topicvarchar(100) NULL消息主题msg_tagvarchar(100) NULLTagmsg_keyvarchar(100) NULLKeymsg_bodyvarchar(500) NULL消息内容msg_statusint(1) NULL0:未处理;1:已经处理create_timetimestamp NOT NULL记录时间 ###9MQ消息消费表 FieldTypeCommentmsg_idvarchar(50) NULL消息IDgroup_namevarchar(100) NOT NULL消费者组名msg_tagvarchar(100) NOT NULLTagmsg_keyvarchar(100) NOT NULLKeymsg_bodyvarchar(500) NULL消息体consumer_statusint(1) NULL0:正在处理;1:处理成功;2:处理失败consumer_timesint(1) NULL消费次数consumer_timestamptimestamp NULL消费时间remarkvarchar(500) NULL备注 3.2 项目初始化 shop系统基于Maven进行项目管理 3.1.1 工程浏览 父工程shop-parent订单系统shop-order-web支付系统shop-pay-web优惠券服务shop-coupon-service订单服务shop-order-service支付服务shop-pay-service商品服务shop-goods-service用户服务shop-user-service实体类shop-pojo持久层shop-dao接口层shop-api工具工程shop-common 共12个系统 3.1.2 工程关系 3.3 Mybatis逆向工程使用 1代码生成 使用Mybatis逆向工程针对数据表生成CURD持久层代码 ###2代码导入 将实体类导入到shop-pojo工程在服务层工程中导入对应的Mapper类和对应配置文件 3.4 公共类介绍 ID生成器 IDWorkerTwitter雪花算法 异常处理类 CustomerException自定义异常类 CastException异常抛出类 常量类 ShopCode系统状态类 响应实体类 Result封装响应状态和响应信息 4. 下单业务 4.1 下单基本流程 1接口定义 IOrderService public interface IOrderService {/*** 确认订单* param order* return Result*/Result confirmOrder(TradeOrder order); }###2业务类实现 Slf4j Component Service(interfaceClass IOrderService.class) public class OrderServiceImpl implements IOrderService {Overridepublic Result confirmOrder(TradeOrder order) {//1.校验订单//2.生成预订单try {//3.扣减库存//4.扣减优惠券//5.使用余额//6.确认订单//7.返回成功状态} catch (Exception e) {//1.确认订单失败,发送消息//2.返回失败状态}} }###3校验订单 private void checkOrder(TradeOrder order) {//1.校验订单是否存在if(ordernull){CastException.cast(ShopCode.SHOP_ORDER_INVALID);}//2.校验订单中的商品是否存在TradeGoods goods goodsService.findOne(order.getGoodsId());if(goodsnull){CastException.cast(ShopCode.SHOP_GOODS_NO_EXIST);}//3.校验下单用户是否存在TradeUser user userService.findOne(order.getUserId());if(usernull){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(校验订单通过); }###4生成预订单 private Long savePreOrder(TradeOrder order) {//1.设置订单状态为不可见order.setOrderStatus(ShopCode.SHOP_ORDER_NO_CONFIRM.getCode());//2.订单IDorder.setOrderId(idWorker.nextId());//核算运费是否正确BigDecimal shippingFee calculateShippingFee(order.getOrderAmount());if (order.getShippingFee().compareTo(shippingFee) ! 0) {CastException.cast(ShopCode.SHOP_ORDER_SHIPPINGFEE_INVALID);}//3.计算订单总价格是否正确BigDecimal orderAmount order.getGoodsPrice().multiply(new BigDecimal(order.getGoodsNumber()));orderAmount.add(shippingFee);if (orderAmount.compareTo(order.getOrderAmount()) ! 0) {CastException.cast(ShopCode.SHOP_ORDERAMOUNT_INVALID);}//4.判断优惠券信息是否合法Long couponId order.getCouponId();if (couponId ! null) {TradeCoupon coupon couponService.findOne(couponId);//优惠券不存在if (coupon null) {CastException.cast(ShopCode.SHOP_COUPON_NO_EXIST);}//优惠券已经使用if ((ShopCode.SHOP_COUPON_ISUSED.getCode().toString()).equals(coupon.getIsUsed().toString())) {CastException.cast(ShopCode.SHOP_COUPON_INVALIED);}order.setCouponPaid(coupon.getCouponPrice());} else {order.setCouponPaid(BigDecimal.ZERO);}//5.判断余额是否正确BigDecimal moneyPaid order.getMoneyPaid();if (moneyPaid ! null) {//比较余额是否大于0int r order.getMoneyPaid().compareTo(BigDecimal.ZERO);//余额小于0if (r -1) {CastException.cast(ShopCode.SHOP_MONEY_PAID_LESS_ZERO);}//余额大于0if (r 1) {//查询用户信息TradeUser user userService.findOne(order.getUserId());if (user null) {CastException.cast(ShopCode.SHOP_USER_NO_EXIST);}//比较余额是否大于用户账户余额if (user.getUserMoney().compareTo(order.getMoneyPaid().longValue()) -1) {CastException.cast(ShopCode.SHOP_MONEY_PAID_INVALID);}order.setMoneyPaid(order.getMoneyPaid());}} else {order.setMoneyPaid(BigDecimal.ZERO);}//计算订单支付总价order.setPayAmount(orderAmount.subtract(order.getCouponPaid()).subtract(order.getMoneyPaid()));//设置订单添加时间order.setAddTime(new Date());//保存预订单int r orderMapper.insert(order);if (ShopCode.SHOP_SUCCESS.getCode() ! r) {CastException.cast(ShopCode.SHOP_ORDER_SAVE_ERROR);}log.info(订单:[order.getOrderId()]预订单生成成功);return order.getOrderId(); }###5扣减库存 通过dubbo调用商品服务完成扣减库存 private void reduceGoodsNum(TradeOrder order) {TradeGoodsNumberLog goodsNumberLog new TradeGoodsNumberLog();goodsNumberLog.setGoodsId(order.getGoodsId());goodsNumberLog.setOrderId(order.getOrderId());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()]扣减库存[order.getGoodsNumber()个]成功);}商品服务GoodsService扣减库存 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()); }###6扣减优惠券 通过dubbo完成扣减优惠券 private void changeCoponStatus(TradeOrder order) {//判断用户是否使用优惠券if (!StringUtils.isEmpty(order.getCouponId())) {//封装优惠券对象TradeCoupon coupon couponService.findOne(order.getCouponId());coupon.setIsUsed(ShopCode.SHOP_COUPON_ISUSED.getCode());coupon.setUsedTime(new Date());coupon.setOrderId(order.getOrderId());Result result couponService.changeCouponStatus(coupon);//判断执行结果if (result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess())) {//优惠券使用失败CastException.cast(ShopCode.SHOP_COUPON_USE_FAIL);}log.info(订单:[order.getOrderId()]使用扣减优惠券[coupon.getCouponPrice()元]成功);}}优惠券服务CouponService更改优惠券状态 Override public Result changeCouponStatus(TradeCoupon coupon) {try {//判断请求参数是否合法if (coupon null || StringUtils.isEmpty(coupon.getCouponId())) {CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);}//更新优惠券状态为已使用couponMapper.updateByPrimaryKey(coupon);return new Result(ShopCode.SHOP_SUCCESS.getSuccess(), ShopCode.SHOP_SUCCESS.getMessage());} catch (Exception e) {return new Result(ShopCode.SHOP_FAIL.getSuccess(), ShopCode.SHOP_FAIL.getMessage());} }###7扣减用户余额 通过用户服务完成扣减余额 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.changeUserMoney(userMoneyLog);if (result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess())) {CastException.cast(ShopCode.SHOP_USER_MONEY_REDUCE_FAIL);}log.info(订单:[order.getOrderId()扣减余额[order.getMoneyPaid()元]成功]);} }用户服务UserService,更新余额 Override public Result changeUserMoney(TradeUserMoneyLog userMoneyLog) {//判断请求参数是否合法if (userMoneyLog null|| userMoneyLog.getUserId() null|| userMoneyLog.getUseMoney() null|| userMoneyLog.getOrderId() null|| userMoneyLog.getUseMoney().compareTo(BigDecimal.ZERO) 0) {CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);}//查询该订单是否存在付款记录TradeUserMoneyLogExample userMoneyLogExample new TradeUserMoneyLogExample();userMoneyLogExample.createCriteria().andUserIdEqualTo(userMoneyLog.getUserId()).andOrderIdEqualTo(userMoneyLog.getOrderId());int count userMoneyLogMapper.countByExample(userMoneyLogExample);TradeUser tradeUser new TradeUser();tradeUser.setUserId(userMoneyLog.getUserId());tradeUser.setUserMoney(userMoneyLog.getUseMoney().longValue());//判断余额操作行为//【付款操作】if (userMoneyLog.getMoneyLogType().equals(ShopCode.SHOP_USER_MONEY_PAID.getCode())) {//订单已经付款则抛异常if (count 0) {CastException.cast(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY);}//用户账户扣减余额userMapper.reduceUserMoney(tradeUser);}//【退款操作】if (userMoneyLog.getMoneyLogType().equals(ShopCode.SHOP_USER_MONEY_REFUND.getCode())) {//如果订单未付款,则不能退款,抛异常if (count 0) {CastException.cast(ShopCode.SHOP_ORDER_PAY_STATUS_NO_PAY);}//防止多次退款userMoneyLogExample new TradeUserMoneyLogExample();userMoneyLogExample.createCriteria().andUserIdEqualTo(userMoneyLog.getUserId()).andOrderIdEqualTo(userMoneyLog.getOrderId()).andMoneyLogTypeEqualTo(ShopCode.SHOP_USER_MONEY_REFUND.getCode());count userMoneyLogMapper.countByExample(userMoneyLogExample);if (count 0) {CastException.cast(ShopCode.SHOP_USER_MONEY_REFUND_ALREADY);}//用户账户添加余额userMapper.addUserMoney(tradeUser);}//记录用户使用余额日志userMoneyLog.setCreateTime(new Date());userMoneyLogMapper.insert(userMoneyLog);return new Result(ShopCode.SHOP_SUCCESS.getSuccess(),ShopCode.SHOP_SUCCESS.getMessage()); }###8确认订单 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()]状态修改成功); }9小结 Override public Result confirmOrder(TradeOrder order) {//1.校验订单checkOrder(order);//2.生成预订单Long orderId savePreOrder(order);order.setOrderId(orderId);try {//3.扣减库存reduceGoodsNum(order);//4.扣减优惠券changeCoponStatus(order);//5.使用余额reduceMoneyPaid(order);//6.确认订单updateOrderStatus(order);log.info(订单:[orderId]确认成功);return new Result(ShopCode.SHOP_SUCCESS.getSuccess(), ShopCode.SHOP_SUCCESS.getMessage());} catch (Exception e) {//确认订单失败,发送消息...return new Result(ShopCode.SHOP_FAIL.getSuccess(), ShopCode.SHOP_FAIL.getMessage());} }4.2 失败补偿机制 4.2.1 消息发送方 配置RocketMQ属性值 rocketmq.name-server192.168.25.135:9876;192.168.25.138:9876 rocketmq.producer.grouporderProducerGroupmq.order.consumer.group.nameorder_orderTopic_cancel_group mq.order.topicorderTopic mq.order.tag.confirmorder_confirm mq.order.tag.cancelorder_cancel注入模板类和属性值信息 Autowiredprivate RocketMQTemplate rocketMQTemplate;Value(${mq.order.topic})private String topic;Value(${mq.order.tag.cancel})private String cancelTag;发送下单失败消息 Override public Result confirmOrder(TradeOrder order) {//1.校验订单//2.生成预订try {//3.扣减库存//4.扣减优惠券//5.使用余额//6.确认订单} catch (Exception e) {//确认订单失败,发送消息CancelOrderMQ cancelOrderMQ new CancelOrderMQ();cancelOrderMQ.setOrderId(order.getOrderId());cancelOrderMQ.setCouponId(order.getCouponId());cancelOrderMQ.setGoodsId(order.getGoodsId());cancelOrderMQ.setGoodsNumber(order.getGoodsNumber());cancelOrderMQ.setUserId(order.getUserId());cancelOrderMQ.setUserMoney(order.getMoneyPaid());try {sendMessage(topic, cancelTag, cancelOrderMQ.getOrderId().toString(), JSON.toJSONString(cancelOrderMQ));} catch (Exception e1) {e1.printStackTrace();CastException.cast(ShopCode.SHOP_MQ_SEND_MESSAGE_FAIL);}return new Result(ShopCode.SHOP_FAIL.getSuccess(), ShopCode.SHOP_FAIL.getMessage());} }private void sendMessage(String topic, String tags, String keys, String body) throws Exception {//判断Topic是否为空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, tags, keys, body.getBytes());//发送消息rocketMQTemplate.getProducer().send(message); }4.2.2 消费接收方 配置RocketMQ属性值 rocketmq.name-server192.168.25.135:9876;192.168.25.138:9876 mq.order.consumer.group.nameorder_orderTopic_cancel_group mq.order.topicorderTopic创建监听类消费消息 Slf4j Component RocketMQMessageListener(topic ${mq.order.topic}, consumerGroup ${mq.order.consumer.group.name},messageModel MessageModel.BROADCASTING) public class CancelOrderConsumer implements RocketMQListenerMessageExt{Overridepublic void onMessage(MessageExt messageExt) {...} }1回退库存 流程分析 消息消费者 Slf4j Component RocketMQMessageListener(topic ${mq.order.topic},consumerGroup ${mq.order.consumer.group.name},messageModel MessageModel.BROADCASTING ) public class CancelMQListener implements RocketMQListenerMessageExt{Value(${mq.order.consumer.group.name})private String groupName;Autowiredprivate TradeGoodsMapper goodsMapper;Autowiredprivate TradeMqConsumerLogMapper mqConsumerLogMapper;Autowiredprivate TradeGoodsNumberLogMapper goodsNumberLogMapper;Overridepublic void onMessage(MessageExt messageExt) {String msgIdnull;String tagsnull;String keysnull;String bodynull;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(times3){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(r0){//未修改成功,其他线程并发修改log.info(并发修改,稍后处理);}}}else{//4. 判断如果没有消费过...mqConsumerLog new TradeMqConsumerLog();mqConsumerLog.setMsgTag(tags);mqConsumerLog.setMsgKey(keys);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);//记录库存操作日志TradeGoodsNumberLog goodsNumberLog new TradeGoodsNumberLog();goodsNumberLog.setOrderId(mqEntity.getOrderId());goodsNumberLog.setGoodsId(goodsId);goodsNumberLog.setGoodsNumber(mqEntity.getGoodsNum());goodsNumberLog.setLogTime(new Date());goodsNumberLogMapper.insert(goodsNumberLog);//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(mqConsumerLognull){//数据库未有记录mqConsumerLog new TradeMqConsumerLog();mqConsumerLog.setMsgTag(tags);mqConsumerLog.setMsgKey(keys);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);}}} }2回退优惠券 Slf4j Component RocketMQMessageListener(topic ${mq.order.topic},consumerGroup ${mq.order.consumer.group.name},messageModel MessageModel.BROADCASTING ) public class CancelMQListener implements RocketMQListenerMessageExt{Autowiredprivate TradeCouponMapper couponMapper;Overridepublic void onMessage(MessageExt message) {try {//1. 解析消息内容String body new String(message.getBody(), UTF-8);MQEntity mqEntity JSON.parseObject(body, MQEntity.class);log.info(接收到消息);//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(回退优惠券失败);}} }3回退余额 Slf4j Component RocketMQMessageListener(topic ${mq.order.topic},consumerGroup ${mq.order.consumer.group.name},messageModel MessageModel.BROADCASTING ) public class CancelMQListener implements RocketMQListenerMessageExt{Autowiredprivate IUserService userService;Overridepublic void onMessage(MessageExt messageExt) {try {//1.解析消息String body new String(messageExt.getBody(), UTF-8);MQEntity mqEntity JSON.parseObject(body, MQEntity.class);log.info(接收到消息);if(mqEntity.getUserMoney()!null mqEntity.getUserMoney().compareTo(BigDecimal.ZERO)0){//2.调用业务层,进行余额修改TradeUserMoneyLog userMoneyLog new TradeUserMoneyLog();userMoneyLog.setUseMoney(mqEntity.getUserMoney());userMoneyLog.setMoneyLogType(ShopCode.SHOP_USER_MONEY_REFUND.getCode());userMoneyLog.setUserId(mqEntity.getUserId());userMoneyLog.setOrderId(mqEntity.getOrderId());userService.updateMoneyPaid(userMoneyLog);log.info(余额回退成功);}} catch (UnsupportedEncodingException e) {e.printStackTrace();log.error(余额回退失败);}} }4取消订单 Overridepublic void onMessage(MessageExt messageExt) {String body new String(messageExt.getBody(), UTF-8);String msgId messageExt.getMsgId();String tags messageExt.getTags();String keys messageExt.getKeys();log.info(CancelOrderProcessor receive message:messageExt);CancelOrderMQ cancelOrderMQ JSON.parseObject(body, CancelOrderMQ.class);TradeOrder order orderService.findOne(cancelOrderMQ.getOrderId());order.setOrderStatus(ShopCode.SHOP_ORDER_CANCEL.getCode());orderService.changeOrderStatus(order);log.info(订单:[order.getOrderId()]状态设置为取消);return order;}4.3 测试 1准备测试环境 RunWith(SpringRunner.class) SpringBootTest(classes ShopOrderServiceApplication.class) public class OrderTest {Autowiredprivate IOrderService orderService; }###1准备测试数据 用户数据商品数据优惠券数据 ###2测试下单成功流程 Test public void add(){Long goodsIdXXXL;Long userIdXXXL;Long couponIdXXXL;TradeOrder order new TradeOrder();order.setGoodsId(goodsId);order.setUserId(userId);order.setGoodsNumber(1);order.setAddress(北京);order.setGoodsPrice(new BigDecimal(5000));order.setOrderAmount(new BigDecimal(5000));order.setMoneyPaid(new BigDecimal(100));order.setCouponId(couponId);order.setShippingFee(new BigDecimal(0));orderService.confirmOrder(order); }执行完毕后,查看数据库中用户的余额、优惠券数据及订单的状态数据 ###3测试下单失败流程 代码同上。 执行完毕后查看用户的余额、优惠券数据是否发生更改订单的状态是否为取消。 5. 支付业务 5.1 创建支付订单 public Result createPayment(TradePay tradePay) {//查询订单支付状态try {TradePayExample payExample new TradePayExample();TradePayExample.Criteria criteria payExample.createCriteria();criteria.andOrderIdEqualTo(tradePay.getOrderId());criteria.andIsPaidEqualTo(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode());int count tradePayMapper.countByExample(payExample);if (count 0) {CastException.cast(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY);}long payId idWorker.nextId();tradePay.setPayId(payId);tradePay.setIsPaid(ShopCode.SHOP_ORDER_PAY_STATUS_NO_PAY.getCode());tradePayMapper.insert(tradePay);log.info(创建支付订单成功: payId);} catch (Exception e) {return new Result(ShopCode.SHOP_FAIL.getSuccess(), ShopCode.SHOP_FAIL.getMessage());}return new Result(ShopCode.SHOP_SUCCESS.getSuccess(), ShopCode.SHOP_SUCCESS.getMessage()); }5.2 支付回调 5.2.1 流程分析 5.2.2 代码实现 public Result callbackPayment(TradePay tradePay) {if (tradePay.getIsPaid().equals(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode())) {tradePay tradePayMapper.selectByPrimaryKey(tradePay.getPayId());if (tradePay null) {CastException.cast(ShopCode.SHOP_PAYMENT_NOT_FOUND);}tradePay.setIsPaid(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode());int i tradePayMapper.updateByPrimaryKeySelective(tradePay);//更新成功代表支付成功if (i 1) {TradeMqProducerTemp mqProducerTemp new TradeMqProducerTemp();mqProducerTemp.setId(String.valueOf(idWorker.nextId()));mqProducerTemp.setGroupName(payProducerGroup);mqProducerTemp.setMsgKey(String.valueOf(tradePay.getPayId()));mqProducerTemp.setMsgTag(topic);mqProducerTemp.setMsgBody(JSON.toJSONString(tradePay));mqProducerTemp.setCreateTime(new Date());mqProducerTempMapper.insert(mqProducerTemp);TradePay finalTradePay tradePay;executorService.submit(new Runnable() {Overridepublic void run() {try {SendResult sendResult sendMessage(topic, tag, finalTradePay.getPayId(), JSON.toJSONString(finalTradePay));log.info(JSON.toJSONString(sendResult));if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) {mqProducerTempMapper.deleteByPrimaryKey(mqProducerTemp.getId());System.out.println(删除消息表成功);}} catch (Exception e) {e.printStackTrace();}}});} else {CastException.cast(ShopCode.SHOP_PAYMENT_IS_PAID);}}return new Result(ShopCode.SHOP_SUCCESS.getSuccess(), ShopCode.SHOP_SUCCESS.getMessage()); }线程池优化消息发送逻辑 创建线程池对象 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;}使用线程池 Autowired private ThreadPoolTaskExecutor executorService;executorService.submit(new Runnable() {Overridepublic void run() {try {SendResult sendResult sendMessage(topic, tag, finalTradePay.getPayId(), JSON.toJSONString(finalTradePay));log.info(JSON.toJSONString(sendResult));if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) {mqProducerTempMapper.deleteByPrimaryKey(mqProducerTemp.getId());System.out.println(删除消息表成功);}} catch (Exception e) {e.printStackTrace();}} });5.2.3 处理消息 支付成功后支付服务payService发送MQ消息订单服务、用户服务、日志服务需要订阅消息进行处理 订单服务修改订单状态为已支付日志服务记录支付日志用户服务负责给用户增加积分 以下用订单服务为例说明消息的处理情况 1配置RocketMQ属性值 mq.pay.topicpayTopic mq.pay.consumer.group.namepay_payTopic_group2消费消息 在订单服务中配置公共的消息处理类 public class BaseConsumer {public TradeOrder handleMessage(IOrderService orderService, MessageExt messageExt,Integer code) throws Exception {//解析消息内容String body new String(messageExt.getBody(), UTF-8);String msgId messageExt.getMsgId();String tags messageExt.getTags();String keys messageExt.getKeys();OrderMQ orderMq JSON.parseObject(body, OrderMQ.class);//查询TradeOrder order orderService.findOne(orderMq.getOrderId());if(ShopCode.SHOP_ORDER_MESSAGE_STATUS_CANCEL.getCode().equals(code)){order.setOrderStatus(ShopCode.SHOP_ORDER_CANCEL.getCode());}if(ShopCode.SHOP_ORDER_MESSAGE_STATUS_ISPAID.getCode().equals(code)){order.setPayStatus(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode());}orderService.changeOrderStatus(order);return order;}}接受订单支付成功消息 Slf4j Component RocketMQMessageListener(topic ${mq.pay.topic}, consumerGroup ${mq.pay.consumer.group.name}) public class PayConsumer extends BaseConsumer implements RocketMQListenerMessageExt {Autowiredprivate IOrderService orderService;Overridepublic void onMessage(MessageExt messageExt) {try {log.info(CancelOrderProcessor receive message:messageExt);TradeOrder order handleMessage(orderService, messageExt, ShopCode.SHOP_ORDER_MESSAGE_STATUS_ISPAID.getCode());log.info(订单:[order.getOrderId()]支付成功);} catch (Exception e) {e.printStackTrace();log.error(订单支付失败);}} }6. 整体联调 通过Rest客户端请求shop-order-web和shop-pay-web完成下单和支付操作 6.1 准备工作 1配置RestTemplate类 Configuration public class RestTemplateConfig {BeanConditionalOnMissingBean({ RestOperations.class, RestTemplate.class })public RestTemplate restTemplate(ClientHttpRequestFactory factory) {RestTemplate restTemplate new RestTemplate(factory);// 使用 utf-8 编码集的 conver 替换默认的 conver默认的 string conver 的编码集为ISO-8859-1ListHttpMessageConverter? messageConverters restTemplate.getMessageConverters();IteratorHttpMessageConverter? 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;}BeanConditionalOnMissingBean({ClientHttpRequestFactory.class})public ClientHttpRequestFactory simpleClientHttpRequestFactory() {SimpleClientHttpRequestFactory factory new SimpleClientHttpRequestFactory();// msfactory.setReadTimeout(15000);// msfactory.setConnectTimeout(15000);return factory;} }2配置请求地址 订单系统 server.hosthttp://localhost server.servlet.path/order-web server.port8080 shop.order.baseURI${server.host}:${server.port}${server.servlet.path} shop.order.confirm/order/confirm支付系统 server.hosthttp://localhost server.servlet.path/pay-web server.port9090 shop.pay.baseURI${server.host}:${server.port}${server.servlet.path} shop.pay.createPayment/pay/createPayment shop.pay.callbackPayment/pay/callbackPayment6.2 下单测试 RunWith(SpringRunner.class) ContextConfiguration(classes ShopOrderWebApplication.class) TestPropertySource(classpath:application.properties) public class OrderTest {Autowiredprivate RestTemplate restTemplate;Value(${shop.order.baseURI})private String baseURI;Value(${shop.order.confirm})private String confirmOrderPath;Autowiredprivate IDWorker idWorker;/*** 下单*/Testpublic void confirmOrder(){Long goodsIdXXXL;Long userIdXXXL;Long couponIdXXXL;TradeOrder order new TradeOrder();order.setGoodsId(goodsId);order.setUserId(userId);order.setGoodsNumber(1);order.setAddress(北京);order.setGoodsPrice(new BigDecimal(5000));order.setOrderAmount(new BigDecimal(5000));order.setMoneyPaid(new BigDecimal(100));order.setCouponId(couponId);order.setShippingFee(new BigDecimal(0));Result result restTemplate.postForEntity(baseURI confirmOrderPath, order, Result.class).getBody();System.out.println(result);}}6.3 支付测试 RunWith(SpringRunner.class) ContextConfiguration(classes ShopPayWebApplication.class) TestPropertySource(classpath:application.properties) public class PayTest {Autowiredprivate RestTemplate restTemplate;Value(${shop.pay.baseURI})private String baseURI;Value(${shop.pay.createPayment})private String createPaymentPath;Value(${shop.pay.callbackPayment})private String callbackPaymentPath;Autowiredprivate IDWorker idWorker;/*** 创建支付订单*/Testpublic void createPayment(){Long orderId 346321587315814400L;TradePay pay new TradePay();pay.setOrderId(orderId);pay.setPayAmount(new BigDecimal(4800));Result result restTemplate.postForEntity(baseURI createPaymentPath, pay, Result.class).getBody();System.out.println(result);}/*** 支付回调*/Testpublic void callbackPayment(){Long payId 346321891507720192L;TradePay pay new TradePay();pay.setPayId(payId);pay.setIsPaid(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode());Result result restTemplate.postForEntity(baseURI callbackPaymentPath, pay, Result.class).getBody();System.out.println(result);}}odsNumber(1); order.setAddress(“北京”); order.setGoodsPrice(new BigDecimal(“5000”)); order.setOrderAmount(new BigDecimal(“5000”)); order.setMoneyPaid(new BigDecimal(“100”)); order.setCouponId(couponId); order.setShippingFee(new BigDecimal(0)); Result result restTemplate.postForEntity(baseURI confirmOrderPath, order, Result.class).getBody();System.out.println(result); }} ## 6.3 支付测试java RunWith(SpringRunner.class) ContextConfiguration(classes ShopPayWebApplication.class) TestPropertySource(classpath:application.properties) public class PayTest {Autowiredprivate RestTemplate restTemplate;Value(${shop.pay.baseURI})private String baseURI;Value(${shop.pay.createPayment})private String createPaymentPath;Value(${shop.pay.callbackPayment})private String callbackPaymentPath;Autowiredprivate IDWorker idWorker;/*** 创建支付订单*/Testpublic void createPayment(){Long orderId 346321587315814400L;TradePay pay new TradePay();pay.setOrderId(orderId);pay.setPayAmount(new BigDecimal(4800));Result result restTemplate.postForEntity(baseURI createPaymentPath, pay, Result.class).getBody();System.out.println(result);}/*** 支付回调*/Testpublic void callbackPayment(){Long payId 346321891507720192L;TradePay pay new TradePay();pay.setPayId(payId);pay.setIsPaid(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode());Result result restTemplate.postForEntity(baseURI callbackPaymentPath, pay, Result.class).getBody();System.out.println(result);}}
http://www.hkea.cn/news/14263001/

相关文章:

  • 介绍类网站建设策划书范文有诗意的设计公司名字
  • 中国建设银行信用卡旅游卡服务网站哈尔滨市哪里做淘宝网站
  • 南京百度网站排名建站工作室
  • 企业做定制网站的好处网站建设和管理专业
  • 做网站的注意点wordpress 群站
  • 网站建设技术合伙人的技术股份企业的网站建设公司
  • 中恒诚信建设有限公司网站wordpress简单网址导航模板
  • 淄博网站设计公司学校网站建设的不足
  • 做网站用什么语言制作最安全做网站属于印花税哪个范畴
  • 做网站时间网站推广的具体方法
  • 静态企业网站下载服务哪家好网站制作
  • 网站模板源码下载网页设计作业总结
  • 深圳 营销型网站建设太原建设工程信息网站
  • 淮安做网站服务单位用什么软件可以做网站
  • 手机网站建设的影响爱爱做网站
  • 58同城会员网站怎么做嘉兴企业自助建站
  • 网站一键备份wordpress做成网盘
  • 宁津建设局网站闵行区
  • 做外贸 网站邮箱申请医院建设官方网站必要性
  • 九江市建设规划局网站外贸流程图详细
  • 网站宣传推广方案asp.net小型网站开发
  • 建设网站包括哪些wordpress 走马灯
  • 招远网站建设招聘北京天仪建设工程质量检测所网站
  • 做网站属于广告费吗wordpress文章meta
  • wordpress sql插件兰州seo实战优化
  • 青海营销网站建设多少钱外贸建站公司排名
  • 网站建设试题以及答案泉州响应式网站建设
  • 辽阳网站建设辽阳网络营销论文范文
  • 网站关键词seo优化公司网站建设有那些软件
  • 别人冒用我们公司做的网站怎么关掉数字尾巴 wordpress