首页 > 其他分享 >使用支付宝沙箱完成商品下单

使用支付宝沙箱完成商品下单

时间:2024-11-13 18:17:46浏览次数:3  
标签:info 支付宝 log payOrder orderId 订单 下单 沙箱 String

使用支付宝沙箱完成商品下单

一:效果展示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

二:代码实现

1:准备工作:

申请支付宝沙箱账户:

登录 - 支付宝

然后要下载密钥密钥工具来生成密钥;

2:流程分析:

先是用户下单,然后我们接收到用户传入的商品id和用户id,然后我们去创建数据库中的订单,再去调用支付宝的接口,创建支付宝订单,创建完成后,用户付款完成,支付宝会回调,我们在回掉时修改订单的状态就行;然后还要有两个定时任务,一个去检查订单有没有超时的,超时的自动关闭,一个去检查有没有订单已经支付了,但是我们没有接收到支付宝的回调,我们在修改状态

3:代码实现

创建订单:

private final OrderDao orderDao;
private final ProductRPC productRPC;
private final AlipayClient alipayClient;
private final EventBus eventBus;
@Value("${alipay.return_url}")
private String returnUrl;
@Value("${alipay.notify_url}")
private String notifyUrl;

@Override
//创建订单
public PayOrderRes createOrder(ShopCartReq shopCartReq) throws AlipayApiException {
    //现根据用户id和商品去查询有没有调单的情况;
    PayOrder payOrderReq = PayOrder.builder()
            .userId(shopCartReq.getUserId())
            .productId(shopCartReq.getProductId()).build();
    PayOrder unPayOrder = orderDao.queryUnPayOrder(payOrderReq);
    //如果查询存在但是是等待支付的状态我们直接去返回支付的地址,跳转支付
    if (unPayOrder != null && Constants.OrderStatusEnum.PAY_WAIT.equals(unPayOrder.getStatus())) {
        log.info("查询到未支付商品,userId,{},productId,{},orderId,{}", unPayOrder.getUserId(),
                unPayOrder.getProductId(), unPayOrder.getOrderId());
        return PayOrderRes.builder()
                .orderId(unPayOrder.getOrderId())
                .payUrl(unPayOrder.getPayUrl())
                .build();
        //如果订单存在而且是已创建的状态说明订单创建了但是支付宝订单没有创建,这种情况要重新调用支付宝的接口创建订单
    } else if (unPayOrder != null && Constants.OrderStatusEnum.CREATE.equals(unPayOrder.getStatus())) {
        //  调用支付宝沙盒创建支付单
        PayOrder payOrder = doPayOrder(unPayOrder.getProductId(), unPayOrder.getProductName(), unPayOrder.getOrderId(), unPayOrder.getTotalAmount());
        log.info("重新创建拉起订单成功,{}", JSON.toJSONString(payOrder));
        return PayOrderRes.builder()
                .payUrl(payOrder.getPayUrl())
                .orderId(payOrder.getOrderId())
                .build();
    }
    //查询商品,创建订单;
    ProductVO productVO = productRPC.queryByProductId(shopCartReq.getProductId());
    String id = RandomStringUtils.randomNumeric(16);
    orderDao.insert(PayOrder.builder()
            .orderId(id)
            .orderTime(new Date())
            .userId(shopCartReq.getUserId())
            .status(Constants.OrderStatusEnum.CREATE.getCode())
            .productId(shopCartReq.getProductId())
            .productName(productVO.getProductName())
            .totalAmount(productVO.getPrice())
            .build());
    //创建支付宝订单
    PayOrder payOrder = doPayOrder(productVO.getProductId(), productVO.getProductName(), id, productVO.getPrice());
    return PayOrderRes.builder()
            .orderId(id)
            .payUrl(payOrder.getPayUrl())
            .build();
}

创建支付宝订单的方法:

public PayOrder doPayOrder(String productId, String productName, String orderId, BigDecimal totalMount) throws AlipayApiException {
    AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
    //设置回调url
    request.setNotifyUrl(notifyUrl);
    request.setReturnUrl(returnUrl);

    JSONObject bizContent = new JSONObject();
    bizContent.put("out_trade_no", orderId);
    bizContent.put("total_amount", totalMount.toString());
    bizContent.put("subject", productName);
    bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
    request.setBizContent(bizContent.toString());

    String form = alipayClient.pageExecute(request).getBody();
    //封装一个订单对象调用数据库方法改变订单的状态,从创建到等待付款
    PayOrder payOrder = new PayOrder();
    payOrder.setOrderId(orderId);
    payOrder.setPayUrl(form);
    payOrder.setStatus(Constants.OrderStatusEnum.PAY_WAIT.getCode());
    
    orderDao.updateOrderStatusUrl(payOrder);

    return payOrder;
}

然后就是创建订单的controller接口:

@PostMapping("create_pay_order")
public Response<String> createOrder(@RequestBody ShopCartReq shopCartReq) {
    try {
        PayOrderRes order = orderService.createOrder(shopCartReq);
        log.info("创建订单成功order,{}", JSON.toJSONString(order));
        return Response.<String>builder()
                .code(Constants.ResponseCode.SUCCESS.getCode())
                .info(Constants.ResponseCode.SUCCESS.getInfo())
                .data(order.getPayUrl())
                .build();
    } catch (Exception e) {
        log.error("创建订单失败,userId,{},e,{}", shopCartReq.getUserId(), e);
        return Response.<String>builder()
                .code(Constants.ResponseCode.UN_ERROR.getCode())
                .info(Constants.ResponseCode.UN_ERROR.getInfo())
                .build();
    }
}

设置回调地址:

notify_url: http://wfw-awei.nat300.top/api/v1/alipay/alipay_notify_url
return_url: https://gaga.plus
gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do

然后写回调的controller方法:

@PostMapping("alipay_notify_url")
public String checkOrderSucess(HttpServletRequest request) {
    try {
        log.info("接收到支付回调,支付状态:{}", request.getParameter("trade_status"));
        //判断回调的支付状态,如果是已支付我们再进行下一步操作
        if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
            Map<String, String> params = new HashMap<>();
            Map<String, String[]> parameterMap = request.getParameterMap();
            for (String name : parameterMap.keySet()) {
                params.put(name, request.getParameter(name));
            }
            String tradeNo = params.get("out_trade_no");
            String payment = params.get("gmt_payment");
            String alipayTradeNo = params.get("trade_no");
            String sign = params.get("sign");
            String content = AlipaySignature.getSignCheckContentV1(params);
            log.info("验签开始");
            //验签
            boolean check = AlipaySignature.rsa256CheckContent(content, sign, alipayPublicKey, "UTF-8");
            log.info("验签结果:{}",check);
            if (check){
                log.info("支付回调,交易名称,{}",params.get("subject"));
                log.info("支付回调,交易状态,{}",params.get("trade_status"));
                log.info("支付回调,支付宝交易凭证号,{}",alipayTradeNo);
                log.info("支付回调,商户订单号,{}",tradeNo);
                log.info("支付回调,校验金额,{}",params.get("total_amount"));
                log.info("支付回调,买家在支付宝的唯一id,{}",params.get("buyer_id"));
                log.info("支付回调,买家付款时间,{}",payment);
                log.info("支付回调,买家付款金额,{}",params.get("buyer_pay_amount"));
                log.info("支付回调,更新订单,{}",tradeNo);
                //验签成功将订单的状态更改
                orderService.checkOrderPaySucess(tradeNo);
            }
        }
        return "sucess";
    } catch (Exception e) {
            log.error("创建订单异常{}",e);
            return "false";
    }
}

更改订单状态的service方法:

@Override
public void checkOrderPaySucess(String tradeNo) {
    log.info("修改订单,{}",tradeNo);
    PayOrder payOrder = new PayOrder();
    payOrder.setOrderId(tradeNo);
    payOrder.setStatus(Constants.OrderStatusEnum.PAY_SUCCESS.getCode());
    orderDao.updateOrderStatus(payOrder);
    eventBus.post(JSONObject.toJSONString(payOrder));
}

这个evenbus相当于一个消息队列,但是是本地的;

设置eventbus:

创建一个接收者:

@Component
@Slf4j
public class OrderSuccessLisener {
    @Subscribe
    public void handleEvent(String successMessage){
        log.info("支付操作完成,可以发货,返利,等");
    }
}

将接收者注册:

@Bean
public EventBus eventBus(OrderSuccessLisener orderSuccessLisener){
    EventBus eventBus = new EventBus();
    eventBus.register(orderSuccessLisener);
    return eventBus;
}

然后上面的就是发送消息的方法;post,接收者加上 @Subscribe表示订阅

还有两个任务:

1:修改超时订单:

 @Scheduled(cron = "0 0/10 * * * ?")
    //每10分钟执行一次方法
    public void exec() {
        try {
            //查询所有超时的订单
            List<String> orderIds = orderService.queryTimeOutOrder();
            //没有直接返回
            if (orderIds.isEmpty() || orderIds == null) {
                log.info("定时任务,无超时订单");
                return;
            }
            //将所有超时订单的状态改为close
            for (String orderId : orderIds) {
                orderService.checkOrderPayClose(orderId);
                log.info("定时订单,超时订单关闭,orderid:{}", orderId);
            }
        } catch (Exception e) {
            log.error("定时任务,超时关闭失败{}",e);
        }

2:查找支付成功未回调的,数据库状态未更改的订单

@Scheduled(cron = "0/3 * * * * ?")
//每3秒执行一次
public void exec() throws AlipayApiException {
    try {
        //查询下单超过1分种,且还是等待支付状态的订单
        List<String> orderIds = orderService.queryNoPayNotifyOrder();
        //如果没有直接返回
        if (orderIds.isEmpty() || orderIds == null) {
            log.info("无未支付成功订单");
            return;
        }
        //遍历每一个订单,查看支付宝订单状态,如果是付款成功我们就更改数据库状态(可能是回调出现问题)
        for (String orderId : orderIds) {
            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
            AlipayTradeQueryModel alipayTradeQueryModel = new AlipayTradeQueryModel();
            alipayTradeQueryModel.setOutTradeNo(orderId);
            request.setBizModel(alipayTradeQueryModel);
            String code = alipayClient.execute(request).getCode();
            //支付成功,更改状态
            if (code.equals("10000")){
                orderService.checkOrderPaySucess(orderId);
            }
        }
    } catch (AlipayApiException e) {
        log.info("检测未接收到或未正确处理的支付回调通知失败");
    }
}
e = alipayClient.execute(request).getCode();
            //支付成功,更改状态
            if (code.equals("10000")){
                orderService.checkOrderPaySucess(orderId);
            }
        }
    } catch (AlipayApiException e) {
        log.info("检测未接收到或未正确处理的支付回调通知失败");
    }
}

标签:info,支付宝,log,payOrder,orderId,订单,下单,沙箱,String
From: https://blog.csdn.net/2301_79748665/article/details/143749356

相关文章

  • 支付宝接口代签约失败排查指南
    作为服务商,需要协助没有开发能力的商家接入业务产品和开发应用的载体,经常要用到支付宝的接口代签约功能,然而在使用过程中若是遇到失败的情况,就会让本来是为了提升效率的功能反而拖慢了项目进度,今天我就来简单盘一盘接口代签约失败问题的排查思路,帮助同学快速定位问题原因,效率......
  • Google play用visa虚拟信用卡下单教程
    GooglePay是简单快捷的付款服务,方便在网站和商店等结账。无论预订旅游行程、出外用餐、购买表演门票或想尝试新的体验,都不用再掏出钱包了。在网上或应用程式开始使用非常简单,只需新增付款卡,即可轻松付款。它服务包括GooglePlay图书,GooglePlay游戏,GooglePlay影视,GooglePla......
  • 支付宝支付功能
    支付宝支付官网地址:https://open.alipay.com/支付宝(中国)网络技术有限公司[1]是国内的第三方支付平台,致力于提供“简单、安全、快速”的支付解决方案[2]。支付宝公司从2004年建立开始,始终以“信任”作为产品和服务的核心。旗下有“支付宝”与“支付宝钱包”两个独立品牌。自2......
  • 支付宝退款功能
    支付宝退款功能参考地址:https://opendocs.alipay.com/open/4b7cc5db_alipay.trade.refund?scene=common&pathHash=d98b006d1、引入依赖<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId></depende......
  • 沙箱技术大起底:如何保护你免受网络攻击?
    前言在当今数字化时代,网络安全问题日益突出,各种恶意软件、病毒和网络攻击层出不穷。为了有效防范这些威胁,保护用户的数据安全和隐私,沙箱技术应运而生。本文将深入探讨沙箱技术的奥秘及其应用,帮助读者更好地了解这一重要的网络安全工具。沙箱技术是一种模拟计算环境的安全......
  • 支付宝生活号无限关注无限曝光机,高效引流必备神器
    功能介绍:支付宝生活号无限关注无限曝光无限关注曝光,不限制关注直到上限,引流钩子设置好,懂得都懂设备需求:安卓手机......
  • 沙箱- Miniconda 安装数据分析三个库
    在Miniconda中安装数据分析常用的三个基础库(NumPy、Pandas和Matplotlib)可以按照以下步骤进行:打开命令提示符(Windows)或终端(macOS/Linux)。确保Miniconda已正确安装并配置在环境变量中。可以在命令提示符或终端中输入condainfo--envs来检查环境信息。创建一个新的......
  • 叮点跑腿!一套跑腿下单接单系统!
    大家好,我是Java陈序员。今天,给大家介绍一套开源的跑腿下单接单系统!关注微信公众号:【Java陈序员】,获取开源项目分享、AI副业分享、超200本经典计算机电子书籍等。项目介绍ddrun——一套后端基于Midway3.0、后台采用Nuxt2.x、小程序采用Uniapp实现的跑腿下单接单系统。......
  • 鸿蒙IME Kit高级开发:共享沙箱机制与输入法数据传输
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。HarmonyOS的IMEKit不仅提供了基础......
  • 鸿蒙自定义编辑框与共享沙箱实现个性化输入法与编辑框的交互
    本文旨在深入探讨自定义编辑框与共享沙箱在跨应用数据共享方面的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。在现代应用开发中,用户对于个性化体验......