支付宝支付

想对接支付,就需要申请对应的支付渠道。否则你只能模拟一个支付和支付成功,来走完自己的流程。
目前国内主要有微信支付和支付宝支付两种主流支付方式,但是微信支付不支持个体户,因此这里选择支付宝的沙箱支付。
其实支付流程基本如下图所示:

现在可以先去支付宝开发平台申请资质,https://open.alipay.com/develop/manage
然后直接下载手机版沙箱支付宝。

实现方案

以下是测试用例(java版):

public class PayTest {

    // 「沙箱环境」应用ID - 您的APPID,收款账号既是你的APPID对应支付宝账号。获取地址;https://open.alipay.com/develop/sandbox/app
    public static String app_id = "你的APPID";
    // 「沙箱环境」商户私钥,你的PKCS8格式RSA2私钥
    public static String app_private_key = "你的商户私钥"
    // 「沙箱环境」支付宝公钥
    public static String alipay_public_key = "你的支付宝公钥"
    // 「沙箱环境」服务器异步通知页面路径。如果非公网地址建议使用 natapp 等内网穿透工具
    public static String notify_url = "异步支付结果通知地址";
    // 「沙箱环境」页面跳转同步通知页面路径 需http://格式的完整路径,必须外网可以正常访问,才会同步跳转
    public static String return_url = "同步页面回调地址,可自动返回商户页面";
    // 「沙箱环境」
    public static String gatewayUrl = "支付宝网关地址";
    // 签名方式
    public static String sign_type = "RSA2";
    // 字符编码格式
    public static String charset = "utf-8";

    @Test
    public void test_AliPay() throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl,
                app_id,
                app_private_key,
                "json",
                charset,
                alipay_public_key,
                sign_type);

        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();  // 发送请求的 Request类
        request.setNotifyUrl(notify_url);
//        request.setReturnUrl(return_url);

        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", "daniel82AAAA000032333361X02");  // 我们自己生成的订单编号
        bizContent.put("total_amount", "0.01"); // 订单的总金额
        bizContent.put("subject", "测试商品");   // 支付的名称
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");  // 固定配置
        request.setBizContent(bizContent.toString());

        String form = alipayClient.pageExecute(request).getBody();
        log.info("测试结果:{}", form);
    }
}

 

  1. 这是支付宝沙箱支付 SDK 支付宝扫码的调用案例,本身这个 SDK 支持了支付宝所有的支付方式,非常方便。
  2. 支付宝沙箱不影响实际环境,且容易申请,如果可能,可以申请微信支付、
  3. 案例运行成功后,会拿到一个html表单,这是一个动态表单,直接加载html就可以去往支付界面。

具体实现

创建订单

@RequestMapping(value = "create_pay_order", method = RequestMethod.POST)
    public Response<String> createParOrder(@RequestHeader("Authorization") String token, @RequestParam Integer productId) {
        try {
            // 1. 校验token
            boolean success = authService.checkToken(token);
            if (!success) {
                return Response.<String>builder()
                        .code(Constants.ResponseCode.TOKEN_ERROR.getCode())
                        .info(Constants.ResponseCode.TOKEN_ERROR.getInfo())
                        .build();
            }
            // 2. token解析
            String openId = authService.getOpenId(token);
            assert openId != null;
            log.info("用户商品下单,根据商品ID创建支付单开始 openid:{} productId:{}", openId, productId);

            ShopCartEntity shopCartEntity = ShopCartEntity.builder()
                    .openid(openId)
                    .productId(productId)
                    .build();

            PayOrderEntity orderEntity = orderService.createOrder(shopCartEntity);
            log.info("用户商品下单,根据商品ID创建支付单完成 openid: {} productId: {} orderPay: {}", openId, productId, orderEntity.toString());

            return Response.<String>builder()
                    .code(Constants.ResponseCode.SUCCESS.getCode())
                    .info(Constants.ResponseCode.SUCCESS.getInfo())
                    .data(orderEntity.getPayUrl())
                    .build();


        }catch (Exception e) {
            log.error("用户商品下单,根据商品ID创建支付单失败", e);
            return Response.<String>builder()
                    .code(Constants.ResponseCode.UN_ERROR.getCode())
                    .info(Constants.ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }

 

public interface IOrderService {

    /**
     * 用户下单,通过购物车信息,返回下单后的支付单
     *
     * @param shopCartEntity 简单购物车
     * @return 支付单实体对象
     */
    PayOrderEntity createOrder(ShopCartEntity shopCartEntity);
    
    //... 省略其他方法
    
}    



 @Override
    public PayOrderEntity createOrder(ShopCartEntity shopCartEntity) throws Exception {
        String openid = shopCartEntity.getOpenid();

        // 1. 查询有效的未支付订单
        UnpaidOrderEntity unpaidOrderEntity = orderRepository.queryUnpaidOrder(shopCartEntity);
        if (unpaidOrderEntity != null && unpaidOrderEntity.getPayStatus().equals(PayStatusVO.WAIT)) {
            log.info("创建订单-存在,已存在未支付订单,返回 openid: {} orderId: {} payUrl: {}", openid, unpaidOrderEntity.getOrderId(), unpaidOrderEntity.getPayUrl());
            return PayOrderEntity.builder()
                    .openid(openid)
                    .payStatus(unpaidOrderEntity.getPayStatus())
                    .payUrl(unpaidOrderEntity.getPayUrl())
                    .orderId(unpaidOrderEntity.getOrderId())
                    .build();
        }else if (unpaidOrderEntity != null && unpaidOrderEntity.getPayStatus().equals(PayStatusVO.CREATE)) {
            log.info("创建订单-存在,存在未创建支付单订单,返回 openid: {} orderId: {}", openid, unpaidOrderEntity.getOrderId());
            PayOrderEntity payOrderEntity = this.doPrepayOrder(openid, unpaidOrderEntity.getOrderId(), unpaidOrderEntity.getProductName(), unpaidOrderEntity.getTotalAmount());
            log.info("创建订单-完成,生成支付单。openid: {} orderId: {} payUrl: {}", openid, payOrderEntity.getOrderId(), payOrderEntity.getPayUrl());
            return payOrderEntity;
        }

        // 2. 查询商品
        ProductEntity productEntity = orderRepository.queryProduct(shopCartEntity.getProductId());
        // 如果所购商品已下线
        if (!productEntity.isAvailable()) {
            throw new ChatGPTException(Constants.ResponseCode.ORDER_PRODUCT_ERR.getCode(), Constants.ResponseCode.ORDER_PRODUCT_ERR.getInfo());
        }

        // 3. 保存订单
        OrderEntity orderEntity = this.doSaveOrder(openid, productEntity);

        // 4. 创建支付
        PayOrderEntity payOrderEntity = this.doPrepayOrder(openid, orderEntity.getOrderId(), productEntity.getProductName(), orderEntity.getTotalAmount());
        log.info("创建订单-完成,生成支付单。openid: {} orderId: {} payUrl: {}", openid, orderEntity.getOrderId(), payOrderEntity.getPayUrl());

        return payOrderEntity;
    }
  1. 创建订单前,要查询有效的未支付订单,如果存在直接返回支付宝支付界面。避免创建一堆的订单。
  2. 此外我们做流程分析时候知道,还有可能是订单存在,但无支付单。那么这个时候需要主动创建一条支付单,再返回。
  3. 如果确实需要创建新订单,则需要根据购物车商品ID,查询出对应的商品信息,创建并保存订单,最后再创建支付单更新到订单上。

支付回调

@PostMapping("pay_notify")
    public void payNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        try {
            log.info("支付回调,消息接收 {}", request.getParameter("trade_status"));
            if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
                Map<String, String> params = new HashMap<>();
                Map<String, String[]> requestParams = request.getParameterMap();
                for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
                    String name = (String) iter.next();
                    String[] values = (String[]) requestParams.get(name);
                    String valueStr = "";
                    for (int i = 0; i < values.length; i++) {
                        valueStr = (i == values.length - 1) ? valueStr + values[i]
                                : valueStr + values[i] + ",";
                    }
                    params.put(name, valueStr);
                }
                String tradeNo = params.get("out_trade_no");
                String gmtPayment = params.get("gmt_payment");
                String alipayTradeNo = params.get("trade_no");
                String sign = params.get("sign");
                Double total_amount = Double.valueOf(params.get("total_amount"));
                boolean checkSignature  = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);

                // 支付宝验签通过
                if (checkSignature) {
                    // 验签通过
                    log.info("支付回调,交易名称: {}", params.get("subject"));
                    log.info("支付回调,交易状态: {}", params.get("trade_status"));
                    log.info("支付回调,支付宝交易凭证号: {}", params.get("trade_no"));
                    log.info("支付回调,商户订单号: {}", params.get("out_trade_no"));
                    log.info("支付回调,交易金额: {}", params.get("total_amount"));
                    log.info("支付回调,买家在支付宝唯一id: {}", params.get("buyer_id"));
                    log.info("支付回调,买家付款时间: {}", params.get("gmt_payment"));
                    log.info("支付回调,买家付款金额: {}", params.get("buyer_pay_amount"));
                    log.info("支付回调,支付回调,更新订单 {}", tradeNo);
                    // 更新订单为已支付
                    boolean isSuccess =  orderService.changeOrderPaySuccess(tradeNo, alipayTradeNo, BigDecimal.valueOf(total_amount), dateFormat.parse(gmtPayment));

                    if (isSuccess) {
                        // 发布消息
//                        eventBus.post(tradeNo);
                        rabbitTemplate.convertAndSend(PayNotifyConfig.PAYNOTIFY_EXCHANGE_FANOUT,"", tradeNo);

                    }
                    response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
                }else {
                    response.getWriter().write("<xml><return_code><![CDATA[FAIL]]></return_code></xml>");
                }
            }
        }catch (Exception e) {
            log.error("支付失败", e);
            response.getWriter().write("<xml><return_code><![CDATA[FAIL]]></return_code></xml>");
        }
    }

 

  1. 支付回调主要以支付宝支付的消息通知为主,更新订单并发送消息。这两步操作都是非常快的,不会让支付回调超时。
  2. 所以一般我们不是通过支付回调直接发货,因为发货流程更长,MQ消息解耦则是更好的方式。
  3. 注意 eventBus 是 Guava 的消息总线,类似于 MQ 消息。为了应对高并发已经改为了rabbitmq,如果业务简单可以继续用Guava

到这支付功能基本实现了,不过实际的商品下单支付场景肯定还会复杂,并且还得考虑异常,比如下单未支付,支付未发货,消息通知异常等等。小伙伴们可以思考哦。 

  • 14
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
Django是一个基于Python的开源Web框架,它提供了一套完整的开发工具和库,用于快速构建高效的Web应用程序。支付宝支付是指在Django中集成支付宝支付功能,使用户可以通过支付宝进行在线支付。 要在Django中实现支付宝支付,可以按照以下步骤进行操作: 1. 注册支付宝开发者账号并创建应用:首先,你需要在支付宝开放平台注册一个开发者账号,并创建一个应用。在创建应用时,你会获得一些必要的信息,如App ID、App Key等。 2. 安装支付宝SDK:使用pip命令安装支付宝SDK,可以在Django项目的虚拟环境中执行以下命令: ``` pip install alipay-sdk-python ``` 3. 配置支付宝参数:在Django项目的配置文件中,添加支付宝相关的配置参数,包括App ID、App Key、支付宝公钥、私钥等。 4. 创建支付视图:在Django项目中创建一个视图函数,用于处理用户发起支付请求的逻辑。在该视图函数中,你需要构建支付宝支付接口所需的参数,并将其传递给支付宝SDK进行处理。 5. 处理支付结果回调:支付宝支付完成后,会向你预先设置的回调URL发送异步通知,通知你支付结果。你需要在Django项目中创建一个接收支付结果回调的视图函数,用于处理支付宝发送的异步通知,并校验支付结果的有效性。 以上是实现Django支付宝支付的基本步骤。当然,具体的实现方式还会根据你的需求和业务逻辑有所不同。你可以参考支付宝开放平台提供的文档和示例代码,以及Django官方文档中关于视图函数和URL配置的内容,来更详细地了解和实现支付宝支付功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值