支付服务-----功能实现逻辑

news2025/7/13 2:15:37

支付服务实现逻辑

简单概况一下支付服务的实现逻辑

通过支付宝的沙箱环境来模拟支付功能,用户点击支付宝的链接后给后端发/aliPayOrder请求,封装支付宝需要payVo对象,并且调用 String pay = alipayTemplate.pay(payVo)和 return pay;来调用支付宝沙箱环境提供的支付页面(这里返回的pay是一个html页面,直接给浏览器渲染后就是支付宝提供的支付页面),这是支付宝官方写好了的,模拟支付宝支付的过程,专门用来给开发人员测试用的,用户输入自己的支付宝账号密码成功支付后就会发请求memberOrder.html,这其实就是支付成功后跳转到用户的订单页面,这个页面会呈现用户的所有订单记录,所以这个请求会把用户的订单数据都封装好,并且把这些数据渲染到订单页面,但是刚支付成功的订单的状态还是待支付,这就有问题了,最后通过支付宝支付成功后的异步回调来修改刚支付成功的订单状态为已支付(异步回调其实就是支付成功后支付宝会给一个地址发送一个请求来告诉你支付成功了)

1、支付使用的是支付宝的沙箱环境来模拟测试的

官网:登录 - 支付宝

2、在订单服务的config文件里配置下面的支付宝支付沙箱环境(常量)

package com.saodai.saodaimall.order.config;


import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.saodai.saodaimall.order.vo.PayVo;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * 支付宝支付沙箱环境配置
 */
@ConfigurationProperties(prefix = "alipay")
@Component
@Data
public class AlipayTemplate {

    // 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
    public String app_id;

    // 商户私钥,您的PKCS8格式RSA2私钥
    public String merchant_private_key;

    // 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
    public String alipay_public_key;

    // 服务器[异步通知]页面路径  需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    // 支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息
    public String notify_url;

    // 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    //同步通知,支付成功,一般跳转到成功页
    public String return_url;

    // 签名方式
    private  String sign_type;

    // 字符编码格式
    private  String charset;

    //订单超时时间(用于收单,防止用户支付很慢,导致订单过期自动关了后再支付订单的情况)
    private String timeout = "1m";

    // 支付宝网关; https://openapi.alipaydev.com/gateway.do
    public String gatewayUrl;

    public  String pay(PayVo vo) throws AlipayApiException {

        //AlipayClient alipayClient = new DefaultAlipayClient(AlipayTemplate.gatewayUrl, AlipayTemplate.app_id, AlipayTemplate.merchant_private_key, "json", AlipayTemplate.charset, AlipayTemplate.alipay_public_key, AlipayTemplate.sign_type);
        //1、根据支付宝的配置生成一个支付客户端
        AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl,
                app_id, merchant_private_key, "json",
                charset, alipay_public_key, sign_type);

        //2、创建一个支付请求 //设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(return_url);
        alipayRequest.setNotifyUrl(notify_url);

        //商户订单号,商户网站订单系统中唯一订单号,必填
        String out_trade_no = vo.getOut_trade_no();
        //付款金额,必填
        String total_amount = vo.getTotal_amount();
        //订单名称,必填
        String subject = vo.getSubject();
        //商品描述,可空
        String body = vo.getBody();

        alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
                + "\"total_amount\":\""+ total_amount +"\","
                + "\"subject\":\""+ subject +"\","
                + "\"body\":\""+ body +"\","
                + "\"timeout_express\":\""+timeout+"\","
                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

        String result = alipayClient.pageExecute(alipayRequest).getBody();

        //会收到支付宝的响应,响应的是一个页面,只要浏览器显示这个页面,就会自动来到支付宝的收银台页面
        System.out.println("支付宝的响应:"+result);

        return result;

    }
}

3、在application.properties配置真正自己的沙箱环境配置

#支付宝相关的配置
#应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
alipay.app_id=2021000119644301
#商户私钥,用的是RSA2私钥
alipay.merchant_private_key=MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCNO1TNy1L65dxxrcmYwo452ClW8rpJsshk9fiToCDSC3Fz0SZQlGYwqGxXr0NzzLvf0sHmIK49CXwXfPgYZPSxaCQSJVm7r87sAEoDi75w0gH0dt+m4viN0GzSGYXVdAfO2J/1BqJoNlpVah3vb3UwLIYpVmNRY6TNdDxnZbpB2Hcosjo8PXvEwqU5MS1W16VkRSkEwPUw/gkKLFUrDqbes5JgJeneAkCPuGa18rNMHxugibVKutfj7MFdomLaNMB2hNOapH3matKJ6JZi/uSqBNLWxfr8kUCw4t8tjJjNaisSfqYwjM9EeWTkkbcba02VUvziB6DqFCue9nV0MVkDAgMBAAECggEAYbHHCcw6DGBwyxoiN89tPsouXnztLAnF4UDcwJGl4mYUBr+It3jP75yxxT3xdOsMktlhU2UL4iDre/vwSj+bnBSjzwGTPudwRYQ1rpo+FCDRRV/tea3LrZ2diQAquerXc9gZXg9GzLu8ZRVQu83nzHkgHPwrG6PH3m8nUYbm/qBM2Fq6nH6AyybXdUk8iwNpLvy/wQkfxPIfZglQqHlEW9x96hs+n/GUx/S4mKFxT6L8MNd7K/rez/xPSGzjPcG1+UkI8VeWQLSnBmfFrCVFrl87rXk6x/6gnY5nogFmKafAvip6hR0/+50vGtWqU/HgeyDc9q/xyLwYy4pulgeRkQKBgQDJqiJjx9WRlC5tfUuwGf2puuwCgu+vqofbE0RuSZtBvb92M65yR+ZtuFkZADOu/ldf5+dITtc1+QpUXCxCvyO+l+w2f0S9oHkfhTmIx6A+jH0spvXfVuZOe97kh2YF3wkAJMd2XBUOEN2xLSeqf62aQxAtfB0zGGZ5iCnoWGbPRwKBgQCzSNPg2XsBb0YVLHtfSOQfuIn7NRHyjznya/9d5cP2HTXgQYMVoJDTKP8ZOwmDFWkRf/DRJEmUGaV5+nJpXa8fyBTkHCCzAEzu8CK2zVQuLPPG9TQXh3t8STEruAu3Sq99LtF8kDhA/8MrmgXmMyhqJGN+jBhwGLq7RekUOg7eZQKBgHLUGpLgZd5oFuunTaKvmf28fsiLT/mhy4vV88Asz2fmqI+gq/NMt4vATZNrxwIctxnYDZzhr69+5//TICy9c5gCH7GEVFr5dh6ZmIIm0TrsehYj15rde3QzGl7cLh6nuhNH3f+qPR7uQZ2yTYTLAMn2585Ofr3qZedLvjkbpSbfAoGBAJZOWFQKALYTNA5MXKJl2ds+O2//7iwNJ+e140I1fzS3CJQaWGupUcG2fSgJ9s+PA6dIO/0bDxS666B397Oed1ONyvXzHvbzKYyohnH7crfDuBz1NdcEHuLz+eVNR4VDeBzbQ4XK416bDmVfm9KC0T8rgr51dYeFNAgNdHsgsZaBAoGAF4sYuVYF2iv9ZTmYMbf9DNv5Px25v2j2RD0pyW+haR2Jq6NqLlGwV/wnFDNAR1BTnFh3vNM1loaw897qORW8bNnAhDGH91jz+pSiCfV4mu9CXDoIw/ZxBfgdxGX7FI7EWPtSG3qb029Vtezks0OW9VROC3I0qePqVeLF8rV6tuE=
#支付宝公钥
alipay.alipay_public_key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAh3IVA56nyTr1Gt33gC5RAbtIVh+pMg1z9ad3VC5h0QPyU0dHYS+j4PbDjeR7kA/Gz3Q7gcp1vo+H4NTBeaQ3m0vG/+UW2wuT6GNeNT8g59gDElE9LtSpqZzsHZMFHKzsvY5n/2v8ADrF16t/TfNnsKvkSCO7Rtcc2mJZtBvZF/APXLn4mbdSs8v5f4o4/RU/iKyKjIUiWfl58JCLD0JYVMxGUcv1Sh9q+1irv4KrP+J/L77eaJ6FiXHX7aXxhsPZQnHy+4KUsjgst1vuYlhpTX9h9GSKiBlFvjTamQhrPtfPfkqa0bsHHmOjToE6gatwDFER0f0kH5gxgo1x1HK0+QIDAQAB
#异步回调地址(支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息)
alipay.notify_url=http://vtyk0jgqvh.51xd.pub/payed/notify
#同步通知地址(支付成功后跳转到指定的地址,这里是跳到最终的订单页面)
alipay.return_url=http://member.saodaimall.com/memberOrder.html
#签名方式
alipay.sign_type=RSA2
alipay.charset=utf-8
#支付宝网关
alipay.gatewayUrl=https://openapi.alipaydev.com/gateway.do
spring.mvc.date-format=yyyy-MM-dd HH:mm:ss

上面要配置的内容有应用ID、商户私钥、支付宝公钥、异步回调地址、同步通知地址即可,然后再沙箱中配置好商户的公钥即可

(1)在上面的官网查看APPID

(2)选择支付加密方式为RSA2(非对称加密方式)

RSA2(非对称加密方式)图解

在这里也就是商户和支付宝两者之间有两对密钥,每一对都是一把公钥一把私钥,其中支付宝的私钥是只有支付宝官方核心人员才知道的

点击上图的查看就可以更换密钥

下载支付宝密钥生成器生成密钥

生成的应用私钥是要配置到支付宝的组件配置中去的,应用公钥给支付宝的沙箱后支付宝也会告诉你一个支付宝的公钥,这个要配置到支付宝的组件配置中。

图解:上面的配置商户私钥(自己的私钥)alipay.merchant_private_key的值就是上面生成密钥的应用私钥,把上面应用公钥(商户公钥)复制到下面公钥字符的区域(其实就是把你自己的公钥(商户公钥)告诉支付宝),点击保存设置后支付宝就知道了你的公钥,然后它会告诉你它的公钥是什么,直接复制并配置到application.properties配置文件里的支付宝公钥alipay.alipay_public_key的值(只需要在配置文件中配置两把钥匙,还有一把是商户公钥,这把不需要配置,因为点击保持后支付宝已经知道了你的公钥)

4、前台设置点击支付宝支付跳转的链接(发请求/aliPayOrder给后端)

<li>
  <img src="/static/order/pay/img/zhifubao.png" style="weight:auto;height:30px;" alt="">
  <a th:href="'http://order.saodaimall.com/aliPayOrder?orderSn='+${submitOrderResp.order.orderSn}">支付宝</a>
</li>

5、在订单服务的web文件的PayWebController控制器处理前面的发的请求/aliPayOrder

package com.saodai.saodaimall.order.web;

import com.alipay.api.AlipayApiException;
import com.saodai.saodaimall.order.config.AlipayTemplate;
import com.saodai.saodaimall.order.service.OrderService;
import com.saodai.saodaimall.order.vo.PayVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
* 支付宝控制器
**/

@Slf4j
@Controller
public class PayWebController {
    
    @Autowired
    private AlipayTemplate alipayTemplate;
    
    @Autowired
    private OrderService orderService;
    
    
    
    /**
    * 用户下单:支付宝支付
    * 1、让支付页让浏览器展示
    * 2、支付成功以后,跳转到用户的订单列表页
    * @param orderSn
    * @return
    * @throws AlipayApiException
    */
    @ResponseBody
    @GetMapping(value = "/aliPayOrder",produces = "text/html")//produces = "text/html"表示返回的类型是html
    public String aliPayOrder(@RequestParam("orderSn") String orderSn) throws AlipayApiException {
         //getOrderPay方法是为了封装PayVo对象
        PayVo payVo = orderService.getOrderPay(orderSn);
        //这里返回的pay是一个html页面,直接给浏览器渲染就行了
        String pay = alipayTemplate.pay(payVo);
        //        System.out.println(pay);
        return pay;
    }
    
}

getOrderPay方法是为了封装PayVo对象,分流程:

1、根据订单号查询到订单

2、格式化付款金额并封装到PayVo

3、获取订单的第一个订单项,把商品销售属性组合(JSON)作为商品描述

  /**
     * 获取当前订单的支付信息(支付宝支付)
     * @param orderSn
     * @return
     */
    @Override
    public PayVo getOrderPay(String orderSn) {

        PayVo payVo = new PayVo();
        //根据订单号查询到订单
        OrderEntity orderInfo = this.getOrderByOrderSn(orderSn);

        //因为数据库保存的是小数点后四位,这里要转为2位(setScale(2, BigDecimal.ROUND_UP)表示保留两位小数点,向上取值)
        BigDecimal payAmount = orderInfo.getPayAmount().setScale(2, BigDecimal.ROUND_UP);
        //设置付款金额
        payVo.setTotal_amount(payAmount.toString());
        //商户订单号
        payVo.setOut_trade_no(orderInfo.getOrderSn());

        //查询订单项的数据
        List<OrderItemEntity> orderItemInfo = orderItemService.list(
                new QueryWrapper<OrderItemEntity>().eq("order_sn", orderSn));
         //获取订单的第一个订单项
        OrderItemEntity orderItemEntity = orderItemInfo.get(0);
        //把商品销售属性组合(JSON)作为商品描述
        payVo.setBody(orderItemEntity.getSkuAttrsVals());
         //把商品sku名字作为设置订单名称
        payVo.setSubject(orderItemEntity.getSkuName());
        return payVo;
    }
package com.saodai.saodaimall.order.vo;

import lombok.Data;

/**
 * 支付宝支付需要用到的数据封装类
 */
@Data
public class PayVo {

    private String out_trade_no; // 商户订单号 必填
    private String subject; // 订单名称 必填
    private String total_amount;  // 付款金额 必填
    private String body; // 商品描述 可空
}

6、第五步处理成功后会执行下面链接的跳转

这个memberOrder.html其实就是订单服务的所有订单界面(用户的所有订单)

#同步通知,支付成功,一般跳转到成功页
alipay.return_url=http://member.saodaimall.com/memberOrder.html

7、在会员服务的web包的MemberWebController控制器来处理请求/memberOrder.html(这里进行了分页处理)

package com.saodai.saodaimall.member.web;

import com.alibaba.fastjson.JSON;
import com.saodai.common.utils.R;
import com.saodai.saodaimall.member.feign.OrderFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 *支付宝支付成功后回调页面处理器
 **/

@Controller
public class MemberWebController {


    @Autowired
    private OrderFeignService orderFeignService;

    @GetMapping(value = "/memberOrder.html")
    public String memberOrderPage(@RequestParam(value = "pageNum",required = false,defaultValue = "0") Integer pageNum,
                                  Model model, HttpServletRequest request) {

        //获取到支付宝给我们转来的所有请求数据
        //request,验证签名


        //查出当前登录用户的所有订单列表数据
        Map<String,Object> page = new HashMap<>();
        page.put("page",pageNum.toString());

        //远程查询订单服务订单数据
        R orderInfo = orderFeignService.listWithItem(page);
        System.out.println(JSON.toJSONString(orderInfo));
        model.addAttribute("orders",orderInfo);

        return "orderList";
    }

}

(1)远程调用订单服务来查询所有订单信息

 /**
     * 分页查询当前登录用户的所有订单信息(用于前台我的订单里的数据回显)
     * @param params
     * @return
     */
    @PostMapping("/listWithItem")
    //@RequiresPermissions("order:order:list")
    public R listWithItem(@RequestBody Map<String, Object> params){
        PageUtils page = orderService.queryPageWithItem(params);

        return R.ok().put("page", page);
    }

(2)OrderServiceImpl的queryPageWithItem方法具体实现

分流程:

1、按会员id去查询所有订单,然后按创建时间做降序排列(也就是最新的订单会在第一个显示)

2、遍历所有订单集合(封装List<OrderEntity>中的订单项的数据)

 /**
     * 分页查询当前登录用户的所有订单信息(用于前台我的订单里的数据回显)
     */
    @Override
    public PageUtils queryPageWithItem(Map<String, Object> params) {

        MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();

        //按会员id去查询所有订单,然后按创建时间做降序排列(也就是最新的订单会在第一个显示)
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
                        .eq("member_id",memberResponseVo.getId()).orderByDesc("create_time")
        );

        //遍历所有订单集合(封装订单项)
        List<OrderEntity> orderEntityList = page.getRecords().stream().map(order -> {
            //根据订单号查询订单项里的数据
            List<OrderItemEntity> orderItemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>()
                    .eq("order_sn", order.getOrderSn()));
            order.setOrderItemEntityList(orderItemEntities);
            return order;
        }).collect(Collectors.toList());

        page.setRecords(orderEntityList);

        return new PageUtils(page);
    }

8、通过支付宝支付成功后的异步回调来修改支付成功后订单页面的订单项的状态

(1)在支付宝沙箱环境配置中有以下配置

这个配置就是表示支付宝支付成功后会有一个支付成功的异步消息发送到这个url地址(特别注意的是这个地址必须是外网能够访问的到得道地址,vtyk0jgqvh.51xd.pub是买了内网穿透后给的地址,外网可以访问到的地址,它和本机的order.saodaimall.com地址是对应的),告诉我们支付成功了,这里就可以通过这个地址来修改订单的状态(也就是把支付宝支付成功后的订单状态由待付款自动修改成已支付状态),这个请求会按固定的时间间隔来发送请求,直到返回“success”才会停止发送请求(发完固定次数也会停止)

#支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息
alipay.notify_url=http://vtyk0jgqvh.51xd.pub/payed/notify

(2)上面的/payed/notify请求由订单服务的listener包的OrderPayedListener控制器来处理

package com.saodai.saodaimall.order.listener;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.saodai.saodaimall.order.config.AlipayTemplate;
import com.saodai.saodaimall.order.service.OrderService;
import com.saodai.saodaimall.order.vo.PayAsyncVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;


/**
* 订单支付成功控制器(支付宝支付成功后的异步通知)
* 支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息
* 只要收到支付宝的异步通知,返回 success 支付宝便不再通知(在通知之前需要验签)
*/
@RestController
public class OrderPayedListener {
    
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private AlipayTemplate alipayTemplate;
    
    @PostMapping(value = "/payed/notify")
    public String handleAlipayed(PayAsyncVo asyncVo, HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException {
        // 获取支付宝POST过来反馈信息
        //TODO 需要验签
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                    : valueStr + values[i] + ",";
            }
            //乱码解决,这段代码在出现乱码时使用
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        
        //alipayTemplate.getAlipay_public_key()是支付宝公钥 alipayTemplate.getCharset()字符编码格式 alipayTemplate.getSign_type()签名方式
        boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayTemplate.getAlipay_public_key(),
                                                          alipayTemplate.getCharset(), alipayTemplate.getSign_type()); //调用SDK验证签名
        
        if (signVerified) {
            System.out.println("签名验证成功...");
            //去修改订单状态
            String result = orderService.handlePayResult(asyncVo);
            return result;
        } else {
            System.out.println("签名验证失败...");
            return "error";
        }
        
    }
    //        for (String key:requestParams.keySet()){
    //            String value = request.getParameter(key);
    //            System.out.println("key: "+key+"=======>value"+value);
    //        }
    //        System.out.println("asyncVo:"+asyncVo);
    //        System.out.println("----------------------------");
    //        System.out.println("requestParams"+requestParams);
    //        return "success";
    
}
package com.saodai.saodaimall.order.vo;

import lombok.Data;
import lombok.ToString;

import java.util.Date;

/**
 * 支付的异步vo(用于下单付款后修改订单的状态为已付款)
 */
@ToString
@Data
public class PayAsyncVo {

    private String gmt_create;
    private String charset;
    private String gmt_payment;
    private Date notify_time;
    private String subject;
    private String sign;
    private String buyer_id;//支付者的id
    private String body;//订单的信息
    private String invoice_amount;//支付金额
    private String version;
    private String notify_id;//通知id
    private String fund_bill_list;
    private String notify_type;//通知类型; trade_status_sync
    private String out_trade_no;//订单号
    private String total_amount;//支付的总额
    private String trade_status;//交易状态  TRADE_SUCCESS
    private String trade_no;//流水号
    private String auth_app_id;//
    private String receipt_amount;//商家收到的款
    private String point_amount;//
    private String app_id;//应用id
    private String buyer_pay_amount;//最终支付的金额
    private String sign_type;//签名类型
    private String seller_id;//商家的id

}

(3)上面控制器的代码都是固定的,唯一是自己业务处理的代码就一句

唯一是自己业务处理:String result = orderService.handlePayResult(asyncVo);

  /**
     * 处理支付宝的支付结果(支付宝异步通知)
     * @param asyncVo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String handlePayResult(PayAsyncVo asyncVo) {

        //保存交易流水信息
        PaymentInfoEntity paymentInfo = new PaymentInfoEntity();
        //订单号(对外业务号)
        paymentInfo.setOrderSn(asyncVo.getOut_trade_no());
        //支付宝交易流水号
        paymentInfo.setAlipayTradeNo(asyncVo.getTrade_no());
        //支付总金额
        paymentInfo.setTotalAmount(new BigDecimal(asyncVo.getBuyer_pay_amount()));
        //交易内容
        paymentInfo.setSubject(asyncVo.getBody());
        //支付状态
        paymentInfo.setPaymentStatus(asyncVo.getTrade_status());
        //创建时间
        paymentInfo.setCreateTime(new Date());
        //回调时间
        paymentInfo.setCallbackTime(asyncVo.getNotify_time());
        //添加到数据库中
        this.paymentInfoService.save(paymentInfo);

        //修改订单状态
        //获取当前状态 TRADE_SUCCESS
        String tradeStatus = asyncVo.getTrade_status();

        //TRADE_SUCCESS是支付宝提供的表示订单状态的常量(表示商家支持的可以退款的支付成功)TRADE_FINISHED表示商家不支持退款的支付成功
        if (tradeStatus.equals("TRADE_SUCCESS") || tradeStatus.equals("TRADE_FINISHED")) {
            //获取订单号(订单号是自己系统生成的订单号)
            String orderSn = asyncVo.getOut_trade_no();
            //orderSn是订单号 OrderStatusEnum.PAYED.getCode()是PAYED(1,"已付款")  PayConstant.ALIPAY支付类型
             this.updateOrderStatus(orderSn,OrderStatusEnum.PAYED.getCode(), PayConstant.ALIPAY);
        }

        return "success";
    }

    /**
     * 修改订单状态(其实就是把订单状态改成已付款)
     * @param orderSn  订单号
     * @param code  订单状态
     * @param payType  支付类型
     */
    private void updateOrderStatus(String orderSn, Integer code,Integer payType) {

        this.baseMapper.updateOrderStatus(orderSn,code,payType);
    }
<!--    修改订单状态-->
<update id="updateOrderStatus">
  UPDATE oms_order
  SET `status` = #{code},modify_time = NOW(),pay_type = #{payType},payment_time = NOW()
  WHERE order_sn = #{orderSn}
</update>
package com.saodai.saodaimall.order.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

/**
 * 保存交易流水信息
 */
@Data
@TableName("oms_payment_info")
public class PaymentInfoEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * id
	 */
	@TableId
	private Long id;
	/**
	 * 订单号(对外业务号)
	 */
	private String orderSn;
	/**
	 * 订单id
	 */
	private Long orderId;
	/**
	 * 支付宝交易流水号
	 */
	private String alipayTradeNo;
	/**
	 * 支付总金额
	 */
	private BigDecimal totalAmount;
	/**
	 * 交易内容
	 */
	private String subject;
	/**
	 * 支付状态
	 */
	private String paymentStatus;
	/**
	 * 创建时间
	 */
	private Date createTime;
	/**
	 * 确认时间
	 */
	private Date confirmTime;
	/**
	 * 回调内容
	 */
	private String callbackContent;
	/**
	 * 回调时间
	 */
	private Date callbackTime;

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/74619.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

A-LEVEL经济例题解析及练习Economic Question

每日一练 例题 Question: Consumer surplusA. Find Marginal Buyer’s WTP (Willingness to Pay) at Q10. B. Find Consumer Surplus for P30. Suppose P falls to $20. How much will Consumer Surplus increase due to: C. buyers entering the market D. existing buyers pa…

mysql8安装过程

1下载地址 https://downloads.mysql.com/archives/community/ 根据自己电脑系统环境选择操作系统和版本&#xff0c;本人选择下载的是windows 64位&#xff0c; 2.创建并编写my.ini文件 创建一个文本文档将文件名改为my后缀为ini my.ini配置其中basedir跟datadir自行根据加…

发布了二十年的《敏捷宣言》是否依然适用?

敏捷宣言已经诞生二十年&#xff0c;这份简短却“颠覆”规则的文件&#xff0c;帮助我们将产品开发交付的方式&#xff0c;从长途运输变成了“次日达”一样的存在。当下的我们正处在一个持续创新的世界&#xff0c;面对技术变革洪流&#xff0c;有时候我们可能会产生思考&#…

day42 文件包含LFIRFI伪协议编码算法代码审计

前言&#xff1a; #知识点&#xff1a; 1、解释-什么是文件包含 2、分类-本地LFI&远程RFI 3、利用-配合上传&日志&会话 4、利用-伪协议&编码&算法等 #核心知识&#xff1a; 1、本地包含LFI&远程包含RFI-区别 一个只能包含本地&#xff0c;一个可…

操作系统例题合集(持续更新)

传送门 由于操作系统知识太多&#xff0c;再加上我总结的比较细&#xff0c;所以一片放不下&#xff0c;拆分成了多篇文章。 操作系统笔记——概述、进程、并发控制 操作系统笔记——储存器管理、文件系统、设备管理 操作系统笔记——Linux系统实例分析、Windows系统实例分析 …

模拟和矢量信号源进阶使用技巧

前言 通常射频信号源的简单应用通常只是输入频率、功率&#xff0c;加上一些模拟、数字调制&#xff0c;然而要充分挖掘出信号源的潜力和性能需要更多的技巧。本应用指南会告诉您可以通过更多的方式提高射频信号源输出信号的质量&#xff0c;具体内容包括&#xff1a; 1. 提高…

【LeetCode_字符串_逻辑分析】6. Z 字形变换

目录考察点第一次&#xff1a;2022年12月9日10:58:17解题思路代码展示题目描述6. Z 字形变换 将一个给定字符串 s 根据给定的行数 numRows &#xff0c;以从上往下、从左到右进行 Z 字形排列。 比如输入字符串为 “PAYPALISHIRING” 行数为 3 时&#xff0c;排列如下&#xf…

DAP组件外部服务开发说明

DAP数据分析平台主要是为了满足企业数据分析的需要而开发的一款产品&#xff0c;不同于一般的BI平台&#xff0c;DAP数据分析平台更侧重数据的聚合&#xff0c;平台预置有数据源注册、ODS注册与管理、数仓配置与数据聚合&#xff0c;从而实现企业业务数据的统一&#xff0c;构建…

不掌握这些坑,你敢用BigDecimal吗?

背景 一直从事金融相关项目&#xff0c;所以对BigDecimal再熟悉不过了&#xff0c;也曾看到很多同学因为不知道、不了解或使用不当导致资损事件发生。 所以&#xff0c;如果你从事金融相关项目&#xff0c;或者你的项目中涉及到金额的计算&#xff0c;那么你一定要花时间看看…

C++ 特殊类的设计

文章目录1. 设计一个只能在堆上创建对象的类2. 设计一个只能在栈上创建对象的类3. 设计一个类不能被拷贝4. 设计一个类 不能被继承5. 设计一个类&#xff0c;只能创建一个对象前言&#xff1a; 在本文中&#xff0c;我们掌握几种常见的特殊类的设计。1. 设计一个只能在堆上创建…

微信小程序使用vant 和 mobx 自动定义Tabbar

vant 和 mobx 自动定义Tabbar 在此案例中&#xff0c;用到的主要知识点如下&#xff1a; 自定义组件 Vant 组件库 MobX 数据共享 组件样式隔离 组件数据监听器 组件的 behaviors Vant 样式覆盖 1.首先需要给我们的app.json 配置tabBar “custom”&#xff1a;true 注意点&…

代码随想录算法训练营第五十九天| LeetCode503. 下一个更大元素 II、LeetCode42. 接雨水

一、LeetCode503. 下一个更大元素 II 1&#xff1a;题目描述&#xff08;503. 下一个更大元素 II&#xff09; 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个元素的 下一个更大元素 。 数字 x 的…

实践 DevOps 测试策略

什么是 DevOps 测试策略&#xff1f; DevOps 的一个重要组成部分是持续集成/持续交付(CI/CD)&#xff0c;在 CI 和 CD 之间的就是持续测试。 如果不进行持续测试&#xff0c;将会出现&#xff1a; 缺陷的泄漏软件延期交付客户不满意DevOps 测试策略的好处 可以提供更快的反…

如何在vscode、remix中结合hardhat编译部署合约

创建 hardhat 工程 # 创建npm空项目&#xff0c;注意这里要选择合约项目对应的文件目录 npm init # 安装 hardhat 环境&#xff0c;这里安装的版本 2.11.1 npm install --save-dev hardhat2.11.1 # 创建工程 npx hardhat首先创建 npm 空项目&#xff0c;注意这里要选择合约项目…

Linux编程环境

一、实验目的 1&#xff0e;熟悉Linux下C语言程序设计的基本步骤 2&#xff0e;掌握gcc编译器的各种参数的使用方法 3&#xff0e;掌握gcc编译器创建函数库的方法 4&#xff0e;掌握gdb调试程序的方法 5&#xff0e;掌握多文件编译中的makefile的用法 二、实验软硬件要求…

matlab学习笔记(八)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 matlab学习笔记&#xff08;八&#xff09;一、傅里叶变换的MATLAB求解二、连续时间信号的频谱图三、MATLAB分析LTI系统的频率特性一、傅里叶变换的MATLAB求解 MATLAB的symb…

大学生网页设计制作作业实例代码 (全网最全,建议收藏) HTML+CSS+JS

文章目录&#x1f4da;web前端期末大作业 (1500套) 集合一、网页介绍二、网页集合三、作品演示A电影主题B漫画主题C商城主题D家乡主题E旅游主题F餐饮/美食主题G环境主题H游戏主题I 个人主题K体育主题L博客主题M汽车主题N文化主题P美妆主题Q企业主题R教育主题S其他主题&#x1f…

Docker的私有仓库部署——Harbor

一.Docker原生私有仓库—— Registry 1.1 Registry的简单了解 关于Docker的仓库分为私有库和公有仓库&#xff0c;共有仓库只要在官方注册用户&#xff0c;登录即可使用。但对于仓库的使用&#xff0c;企业还是会有自己的专属镜像&#xff0c;所以私有库的搭建也是很有必要的…

力扣(LeetCode)1780. 判断一个数字是否可以表示成三的幂的和(C++)

进制转换 转换 333 进制&#xff0c;如果每一位非 000 即 111 &#xff0c;returntruereturn\ truereturn true (数字 000 除外&#xff09;。 如果任意一位为 222 &#xff0c;returnfalsereturn\ falsereturn false 。 证明: 对于第 ppp 位&#xff0c; 如果 p0p0p0 &#…

数据结构——树和二叉树最全总结(期末复习必备)

目录 树和二叉树 树的基本术语&#xff08;均以上图b为例&#xff09;&#xff1a; 遍历二叉树&#xff1a; 线索二叉树&#xff1a; 树的存储结构&#xff1a; 树与二叉树的转换&#xff08;利用的就是把二叉树和树表示成相同的二叉链表&#xff09;&#xff1a; 森林与二…