• 04-学生选课(课程记录、订单创建、微信支付)


    一、学生选课

    ​ 在学生选课中,需要学员通过学成在线门户网站实现,查看学生的课程购买记录、学生购买课程的下单、学生支付收费课程、分布式任务调度查询支付结果等操作。本次主要是对学成的学生群体来开发对应的功能。

    1.1 需求分析

    本次主要针对学生学科的业务操作,主要功能包括:

    • 学生进入首页课程搜索找到目标课程,进入某个课程的详情页,需要判断是否收费,如果收费需要查询改学员对此课程的购买记录。
    • 课程收费的情况下,学生对此课程会创建出购买课程的订单,完成课程购买的操作。
    • 学生需要进行支付,来完成对课程的购买。
    • 学生可以在学习中心中查看自己所有的所学的课程,包括收费的课程和免费课程。

    学生选课流程如下:

    1.通过首页课程搜索找到目标课程,进入课程详情页.

    • 免费课程的显示
      在这里插入图片描述
    • 收费课程的显示
      在这里插入图片描述
    • 点击价格按钮,跳转到订单页面
      在这里插入图片描述
    • 确认订单并支付成功后,返回课程详情页面,查找学习记录,若学习记录不为初始状态,则显示继续学习
      在这里插入图片描述
    • 点击马上学习按钮后,跳转到课程点播页面
      在这里插入图片描述

    1.2 业务流程分析

    选课时序图

    在这里插入图片描述

    创建订单时序图在这里插入图片描述

    订单支付时序图

    在这里插入图片描述

    微信支付时序图

    在这里插入图片描述

    二、数据分析

    上述的业务主要涉及到两个实体:订单学习记录

    2.1 订单

    由于订单包含的字段太多了,并且我们将其拆分为两张表,一张表示订单基本信息、另外一张表示订单支付信息

    orders

    在这里插入图片描述

    orders_pay

    在这里插入图片描述

    2.2 课程记录表

    课程记录表表达的是用户对每门的学习进度,通过username和coursepubId可以确定唯一的一条记录(最开始我误解了业务流程,认为只要用户看过的小节,这张表都会记录,这样username和coursepubId可以找到多条记录,这样会大大增加表的数据量,所以我们采用只记录用户在该门课上最近看的小节,每当用户访问课程小节时,就修改课程记录表中的teachplanId为该小节id)
    在这里插入图片描述

    三、业务实现

    3.1 查询用户课程记录

    接口设计

    在这里插入图片描述
    controller

    @GetMapping("learnedRecords/myCourseRec/{coursePubId}")
        public CourseRecordDTO getRecordByCoursePubId(@PathVariable Long coursePubId) {
    
            String username = UAASecurityUtil.getUser().getUsername();
    
            CourseRecordDTO dto = courseRecordService.getRecordByCoursePubId(coursePubId, username);
    
            return dto;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    service

     /*
        * 业务分析:
        *   1.判断关键数据
        *   2.判断业务数据
        *       判断课程是否处于发布状态
        *           不处于发布状态:若为免费课程则拒绝查看,若为付费课程则根据用户是否付款来给予观看权限
        *   3.根据条件查询用户的学习记录
        *   4.返回学习记录数据
        *       如果有数据返回
        *       如果没有返回空数据
        * */
        public CourseRecordDTO getRecordByCoursePubId(Long coursePubId, String username) {
    
            // 1.判断关键数据
            if (ObjectUtils.isEmpty(coursePubId)||
                    StringUtil.isBlank(username)
            ) {
                ExceptionCast.cast(CommonErrorCode.E_100101);
            }
    
            //2.判断该课程是否下架
            RestResponse response = coursePubIndexApiAgent.getCoursePubIndexById4s(coursePubId);
            CoursePubIndexDTO result = response.getResult();
    
            //课程不曾公开或免费课程下架则抛出异常
            if(result == null || (result.getIs_pub() != 0 && result.getCharge().equals(CourseChargeEnum.CHARGE_NO.getCode()))){
                ExceptionCast.cast(LearningErrorCode.E_202205);
            }
            //  3.根据条件查询用户的学习记录(一个人对一门课只有一个学习记录)
            LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(CourseRecord::getCoursePubId, coursePubId);
            queryWrapper.eq(CourseRecord::getUserName, username);
    
            CourseRecord courseRecord = this.getOne(queryWrapper);
    
            //付费课程若下架则根据用户是否支付来给予观看权限
            if((ObjectUtils.isEmpty(courseRecord) && result.getIs_pub() != 0) || (courseRecord.getPaid() == 0 && result.getIs_pub() != 0)){
                ExceptionCast.cast(LearningErrorCode.E_202205);
            }
    
    
            //  4.返回学习记录数据
            CourseRecordDTO courseRecordDTO = null;
            if (ObjectUtils.isEmpty(courseRecord)) {
            //      如果没有返回空数据
                courseRecordDTO = new CourseRecordDTO();
            } else {
            //      如果有数据返回
                courseRecordDTO = CourseRecordConvert.INSTANCE.entity2dto(courseRecord);
            }
            return courseRecordDTO;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    3.2 创建订单

    在这里插入图片描述
    controller

    @GetMapping("orders/create/{coursePubId}")
        public OrdersDTO createOrder(@PathVariable Long coursePubId) {
    
            LoginUser user = UAASecurityUtil.getUser();
    
            if (ObjectUtils.isEmpty(user)) {
                ExceptionCast.cast(CommonErrorCode.E_100108);
            }
    
            OrdersDTO dto = ordersService.createOrder(coursePubId, user.getUsername());
    
    
            return dto;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    service

    /*
        * 业务分析:
        *   1.判断关键数据
        *       coursePubId   username
        *   2.判断业务数据
        *       课程是否发布
        *       用户是否已经购买该课程
        *   3.保存订单数据
        *       判断订单数据是否存在:coursePubId username(一个人对于一门课只有一个订单)
        *         根据订单支付状态来判断:初始化态
        *           如果没有
        *               创建订单:新建的订单状态为--初始态(orderNo,coursePubId,coursePubName,username,companyId,initPrice,price,status)
        *           如果有
        *              如果订单数据存在,需要获得最新的课程价格并修改订单的价格数据--活动
        *
        *   4.将结果数据转为DTO并返回
        * */
        @Transactional
        public OrdersDTO createOrder(Long coursePubId, String username) {
    
            // 1.判断关键数据
            //      coursePubId   username
            if (ObjectUtils.isEmpty(coursePubId)||
                    StringUtil.isBlank(username)
            ) {
                ExceptionCast.cast(CommonErrorCode.E_100101);
            }
    
            //  2.判断业务数据
            //      课程发布数据
            RestResponse restResponse = searchApiAgent.getPubIndexById4s(coursePubId);
            CoursePubIndexDTO coursePub = restResponse.getResult();
            if (ObjectUtils.isEmpty(coursePub)) {
                ExceptionCast.castWithCodeAndDesc(restResponse.getCode(),restResponse.getMsg());
            }
    
            //  查看用户是否购买过该课程
            Orders one = this.lambdaQuery().eq(Orders::getStatus, OrderDealStatusEnum.ORDER_DEAL_CLOSED_STATUS.getCode()).or().eq(Orders::getStatus, OrderDealStatusEnum.ORDER_DEAL_CLOSED_STATUS.getCode()).one();
            if(!ObjectUtils.isEmpty(one)){
                ExceptionCast.cast(OrderErrorCode.E_160021);
            }
    
    
    
            //  3.保存订单数据
            //      判断订单数据是否存在:coursePubId username(一个人对于一门课只有一个订单)
            //      根据订单支付状态来判断:初始化态
            //  select * from orders where username = ? and coursePubid = ? and status = ?
            LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Orders::getUserName, username);
            queryWrapper.eq(Orders::getCoursePubId, coursePubId);
            queryWrapper.eq(Orders::getStatus,new Integer(OrderDealStatusEnum.ORDER_DEAL_INIT_STATUS.getCode()) );
    
            Orders orders = this.getOne(queryWrapper);
    
    
            boolean result = false;
            //若订单不存在则创建订单
            if (ObjectUtils.isEmpty(orders)) {
    
                orders = new Orders();
    
                // 订单编号:有学成的标识+时间+唯一标识
                orders.setOrderNo(PaymentUtil.genUniquePayOrderNo());
                orders.setCoursePubId(coursePubId);
                orders.setCoursePubName(coursePub.getName());
                orders.setCompanyId(coursePub.getCompanyId());
                orders.setUserName(username);
                orders.setInitialPrice(coursePub.getPrice());
                orders.setPrice(coursePub.getPrice());
                orders.setStatus(new Integer(OrderDealStatusEnum.ORDER_DEAL_INIT_STATUS.getCode()));
    
                result = this.save(orders);
    
    
            } else{
                // 修改订单的价格
                // 如果订单数据存在,需要获得最新的课程价格并修改订单的价格数据--活动
                LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(Orders::getPrice, coursePub.getPrice());
                updateWrapper.set(Orders::getChangeDate, LocalDateTime.now());
                updateWrapper.eq(Orders::getId, orders.getId());
    
                result = this.update(updateWrapper);
    
            }
    
            if (!result) {
                ExceptionCast.cast(OrderErrorCode.E_160015);
            }
    
            //  4.将结果数据转为DTO并返回
            Orders po = this.getById(orders.getId());
    
            OrdersDTO resultDTO = OrderConvert.INSTANCE.entity2dto(po);
    
            return resultDTO;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

    3.3 创建订单支付信息

    controller

     @GetMapping("orderPay/wxPay/createPay")
        public PayCodeUrlResult createPayment(String orderNo) {
    
            LoginUser user = UAASecurityUtil.getUser();
    
            if (ObjectUtils.isEmpty(user)) {
                ExceptionCast.cast(CommonErrorCode.E_100108);
            }
    
            PayCodeUrlResult payment = ordersService.createPayment(orderNo, user.getUsername());
    
            return payment;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    service

     /*
            PS:该方法不管也什么异常,都需要使用PayCodeUrlResult数据进行封装
        * 业务分析:
        *   1.判断关键数据
        *       orderNo username
        *   2.判断业务数据
        *       订单数据
        *           判断是否存在:orderId username status :初始态
    
            特别说明:本次的操作由于无法向外抛出异常,使得事务无法回滚:
                1.操作本地数据
                2.先操作第三方支付系统
            3.保存订单支付数据
            4.和wx平台进行交互获得支付链接地址
        * */
        @GlobalTransactional
        public PayCodeUrlResult createPayment(String orderNo, String username) {
            if(ObjectUtils.isEmpty(orderNo) ){
                ExceptionCast.castWithCodeAndDesc(10010,"订单编号不能为空");
            }
    
            //2.判断业务数据
            //    订单数据
            //        判断是否存在:orderNo username status:初始态
            Orders order = this.lambdaQuery().eq(Orders::getOrderNo, orderNo).eq(Orders::getUserName, username).eq(Orders::getStatus, OrderDealStatusEnum.ORDER_DEAL_INIT_STATUS.getCode()).one();
            if(ObjectUtils.isEmpty(order)){
                ExceptionCast.cast(OrderErrorCode.E_160008);
            }
            //3.保存订单支付数据
            LambdaQueryWrapper payQueryWrapper = new LambdaQueryWrapper<>();
            payQueryWrapper.eq(Pay::getOrderId, order.getId());
            payQueryWrapper.eq(Pay::getUserName, username);
            payQueryWrapper.eq(Pay::getCompanyId, order.getCompanyId());
            payQueryWrapper.eq(Pay::getStatus, PayCodeUrlResult.NOT_PAY);
    
            //3.1 查询是否存在支付数据
            Pay pay = payService.getOne(payQueryWrapper);
            if(ObjectUtils.isEmpty(pay)){
                pay = new Pay();
                pay.setUserName(username);
                pay.setCompanyId(order.getCompanyId());
                pay.setOrderId(order.getId());
                pay.setStatus(PayCodeUrlResult.NOT_PAY);
                pay.setPayMethod(PayCodeUrlResult.WX_PAY_FLAG);
    
                // 实收金额和付款金额在支付后的通知中再去赋值,本次秩序赋值订单金额即可
                pay.setTotalAmount(new BigDecimal(order.getPrice().toString()));
                boolean save = payService.save(pay);
                if(!save){
                    ExceptionCast.cast(OrderErrorCode.E_160009);
                }
            }
            //4.和wx平台进行交互获得支付链接地址
            try{
                WxPayUnifiedOrderRequest payUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
                payUnifiedOrderRequest.setBody(order.getCoursePubName());
                payUnifiedOrderRequest.setOutTradeNo(order.getOrderNo());
    
                Integer price = WxPayUnifiedOrderRequest.yuanToFen(order.getPrice().toString());
                payUnifiedOrderRequest.setTotalFee(price);
    
                // 4.1获得程序服务所在服务的ip地址
                payUnifiedOrderRequest.setSpbillCreateIp(InetAddress.getLocalHost().getHostAddress());
                payUnifiedOrderRequest.setProductId("课程id:"+order.getCoursePubId());
    
                // 4.2通过wxPayService获得统一下单的响应数据
                WxPayUnifiedOrderResult result = wxPayService.unifiedOrder(payUnifiedOrderRequest);
                // 4.3解析响应数据
                PayCodeUrlResult codeUrlResult = new PayCodeUrlResult();
    
                if ("SUCCESS".equalsIgnoreCase(result.getReturnCode()) && "SUCCESS".equalsIgnoreCase(result.getResultCode())) {
                    codeUrlResult = PayCodeUrlResult.success(result.getCodeURL());
                } else {
                    ExceptionCast.cast(OrderErrorCode.E_160011);
                }
                return codeUrlResult;
            }catch (Exception e){
                ExceptionCast.cast(OrderErrorCode.E_160011);
            }
            return null;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    3.4 微信回调接口

    首先我们需要设置回调的地址

    #商户微信公共号或开放平台唯一标识
    weixinpay.app-id = wx
    #商户号
    weixinpay.mch-id = 14
    #商户密钥
    weixinpay.mch-key = T6m9iK7
    #微信回调商户的地址
    weixinpay.notify-url = http://6aa17ecf.cpolar.io
    #商户的支付类型(NATIVE 为扫码支付)
    weixinpay.trade-type = NATIVE
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    controller

     /* 给wx支付平台来调用的方法,没有在Api接口中定义方法 */
        @RequestMapping("order-pay/wx-pay/notify-result")
        public String notifyPayment(HttpServletRequest request) {
            System.out.println("订单支付通知方法开始执行");
            try {
                String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
    
                // 加入自己处理订单的业务逻辑,需要判断订单是否已经支付过,否则可能会重复调用
                // 调用service层处理业务
                payService.notifyPayment(xmlResult);
    
                return WxPayNotifyResponse.success("处理成功!");
            } catch (Exception e) {
                log.error("微信回调结果异常,异常原因{}", e.getMessage());
                return WxPayNotifyResponse.fail(e.getMessage());
            }
    
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    service

    /*
        * 业务操作
        *   1.判断并解析wx通知内容
        *       保证wx支付是成功:returncode和resultcode为SUCCESS
        *       如果支付通知消息失败,无需完成订单服务的业务逻辑操作,抛出异常,使用controller接受并返回wx错误信息
        *   2.修改订单状态
        *
        *       完成消息幂等(wx支付平台会重复发消息)
        *           判断订单是否已经支付
        *               通过订单编号:out_trade_no
        *
        *       PS:如果业务数据操作失败,需要让wx支付平台继续通知,继续通知的方式是业务层对外抛出异常
        *
        *       判断第三方订单金额是否和商户的订单金额是否一致(wx官方特别提醒)
        *
        *       orders:status
        *           判断订单是否存在
        *           判断订单的状态:支付前状态必须初始态
        *           修改内容:
        *               status
        *       pay_orders:支付后的结果
        *           判断订单支付是否存在
        *           判断订单支付的状态:status
        *
        *           修改内容:
        *               status
        *               pay_number
        *               pay_date
        *               receipt_amount
        *               buyer_pay_amount
        *               pay_response
        *
        *   3.给用户支付后的内容创建一个默认的学习记录
        *       在学习中心完成:Feign远程调用
        *
        *
        *   4.返回通知结果-wx平台
        *       如果正常,执行代码就可以
        *       如果数据不正常,业务需要抛出异常
        *           controller会针对service的执行结果来返回数据给wx支付平台
        * */
        @GlobalTransactional
       @GlobalTransactional
        public void notifyPayment(String xmlResultString) {
            // 1.判断并解析wx通知内容
            //      保证wx支付是成功:returncode和resultcode为SUCCESS
            //      如果支付失败,无需完成订单服务的业务逻辑操作
            if (StringUtil.isBlank(xmlResultString)) {
                ExceptionCast.cast(CommonErrorCode.E_100101);
            }
    
            WxPayOrderNotifyResult notifyResult = null;
            try {
                notifyResult = wxPayService.parseOrderNotifyResult(xmlResultString);
            } catch (WxPayException e) {
                log.error(OrderErrorCode.E_160018.getDesc()+" : errMsg {}",e.getMessage());
                ExceptionCast.cast(OrderErrorCode.E_160018);
            }
    
    
            String returnCode = notifyResult.getReturnCode();
            String resultCode = notifyResult.getResultCode();
    
            String outTradeNo = notifyResult.getOutTradeNo();
    
            // 支付通知成功
            if (PayCodeUrlResult.WX_PAY_SUCCESS_FLAG.equalsIgnoreCase(returnCode)&&
                    PayCodeUrlResult.WX_PAY_SUCCESS_FLAG.equalsIgnoreCase(resultCode)
            ) {
    
    
                //  2.修改订单状态
                //      完成消息幂等(wx支付平台会重复发消息)
                //          判断订单是否已经支付
                //              通过订单编号:out_trade_no-->orderNo
                LambdaQueryWrapper ordersQueryWrapper = new LambdaQueryWrapper<>();
                // 创建订单没有支付的查询条件
                ordersQueryWrapper.eq(Orders::getOrderNo, outTradeNo);
                ordersQueryWrapper.eq(Orders::getStatus,new Integer(OrderDealStatusEnum.ORDER_DEAL_INIT_STATUS.getCode()));
    
                Orders order = ordersService.getOne(ordersQueryWrapper);
    
                if (ObjectUtils.isEmpty(order)) {
                    log.error("订单信息不是初始态,订单编号:{}", outTradeNo);
                    return;
                }
    
                // 判断第三方订单金额是否和商户的订单金额是否一致
                // wx订单金额(分)
                Integer totalFee = notifyResult.getTotalFee();
                String toYuan = BaseWxPayResult.fenToYuan(totalFee);
                Float totalFeeFloat = new Float(toYuan);
    
    
                // 商户订单金额(元)
                Float price = order.getPrice();
    
                // 判断金额是否一致
                if (!(totalFeeFloat.equals(price))) {
                    log.error("订单金额与支付金额不一致,订单编号:{}", outTradeNo);
                    return;
                }
    
    
    
    
                //      订单数据:status
                //          判断订单是否存在
                //          判断订单的状态:支付前状态必须初始态
                //          修改内容:
                //              status
                LambdaUpdateWrapper ordersUpdateWrapper = new LambdaUpdateWrapper<>();
                ordersUpdateWrapper.set(Orders::getStatus, new Integer(OrderDealStatusEnum.ORDER_DEAL_PAID_STATUS.getCode()));
                ordersUpdateWrapper.set(Orders::getChangeDate, LocalDateTime.now());
                ordersUpdateWrapper.eq(Orders::getOrderNo,outTradeNo);
    
                boolean orderResult = ordersService.update(ordersUpdateWrapper);
    
                // 如果业务数据操作失败,需要让wx支付平台继续通知,继续通知的方式是业务层对外抛出异常
                if (!orderResult) {
                    ExceptionCast.cast(OrderErrorCode.E_160015);
                }
    
                //      订单支付数据:支付后的结果
                //          判断订单支付是否存在
                //          判断订单支付的状态:status 0
                //          修改内容:
                //              status
                //              pay_number
                //              pay_date
                //              receipt_amount
                //              buyer_pay_amount
                //              pay_response
    
                LambdaQueryWrapper payQueryWrapper = new LambdaQueryWrapper<>();
                payQueryWrapper.eq(Pay::getOrderId,order.getId());
                payQueryWrapper.eq(Pay::getStatus,PayCodeUrlResult.NOT_PAY);
    
                Pay pay = this.getOne(payQueryWrapper);
                if (ObjectUtils.isEmpty(pay)) {
                    log.error("订单支付信息不是未支付,订单编号:{}", outTradeNo);
                    return ;
                }
    
                pay.setStatus(PayCodeUrlResult.PAIED);
                // 记录wx的支付编号
                pay.setPayNumber(notifyResult.getTransactionId());
                // 记录wx支付平台的用户支付时间
                String timeEnd = notifyResult.getTimeEnd();
                DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
                LocalDateTime payTime = LocalDateTime.parse(timeEnd, dateTimeFormatter);
    
                pay.setPayDate(payTime);
    
                Integer settlementTotalFee = notifyResult.getSettlementTotalFee();
                if (!(ObjectUtils.isEmpty(settlementTotalFee))) {
                    String settlementTotalFeeString = BaseWxPayResult.fenToYuan(settlementTotalFee);
                    pay.setReceiptAmount(new BigDecimal(settlementTotalFeeString));
                }
    
    
                Integer cashFee = notifyResult.getCashFee();
                if (!(ObjectUtils.isEmpty(cashFee))) {
                    String cashFeeString = BaseWxPayResult.fenToYuan(cashFee);
                    pay.setBuyerPayAmount(new BigDecimal(cashFeeString));
                }
    
                pay.setPayResponse(xmlResultString);
    
                boolean payResult = this.updateById(pay);
                if (!payResult) {
                    ExceptionCast.cast(OrderErrorCode.E_160017);
                }
    
    
                //  3.给用户支付后的内容创建一个默认的学习记录
                //      在学习中心完成:Feign远程调用
                learningApiAgent.createPaidRecord(order.getUserName(),order.getCoursePubId());
    
                // 支付通知失败
            } else {
                log.error("支付通过内容失败,订单编号:{}", outTradeNo);
    
            }
    
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
  • 相关阅读:
    艾美捷C1q天然蛋白的应用和化学性质说明
    【JavaSE基础】对象的构造及初始化
    应急启动电源+充气一体式方案设计
    Windows 无法访问wsl ubuntu 中 docker 的端口
    很多人觉得程序员岗位不需要沟通能力,是这样吗?
    5.Docker-harbor私有仓库部署与管理
    sandman_nc_2016
    阿里开源的32B大模型到底强在哪里?
    面试必问的分布式锁,你懂了吗?
    【Rust日报】2022-08-11 Rust 1.63.0 stable 正式发布
  • 原文地址:https://blog.csdn.net/qq_42861526/article/details/126364031