Paypal+java 支付接入-程序员宅基地

技术标签: 安卓  java  paypal  

背景说明 :业务需求,需要联合APP完成Paypal的支付接入,于是开始爬坑
第一步:注册获取到paypal的商家账号(注册流程我也不知道)
第二步:登录Paypal开发者中心,创建APP应用获取到clientId和secret

在这里插入图片描述
在这里插入图片描述

第三步:创建沙盒环境下的商户及消费者账号并给消费账号设置余额 9999.99

在这里插入图片描述
!! 我没有使用paypal默认的商家及消费者账号,如果账号有问题建议自己创建对应账号

第四步:编写代码完成支付流程

1.安卓端拿到第二步中创建的 clientId 及商户账号就可以唤起Paypal的支付页面了,所以需要为支付回调做准备
2.安卓端完成商品信息展示,用户点击付款按钮后向后端申请订单,后端生成预付订单信息并返回商品对应信息及订单号
3.安卓端SDK有"customer"字段,这个字段在支付回调时Paypal会返回至回调接口,所以可以用来完成业务逻辑,本人只传了订单号

第五步:设置IPN回调地址并编写回调接口(以下皆以沙盒环境为说明)

沙盒:https://www.sandbox.paypal.com/businessmanage/account/notifications
正式环境:https://www.paypal.com/mep/dashboard

1.设置回调地址,沙盒环境是允许http的,但是正式环境得是https
在这里插入图片描述分割符--------
在这里插入图片描述

3.编写支付回调的代码

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Enumeration;
    /**
     * Paypal IPN异步回调接口
     *
     * @param request
     * @param response
     * @Atuthor yixiu
     * @since 2020/9/25
     * @throws Exception
     */
 public void receivePaypalStatus(HttpServletRequest request, HttpServletResponse response) throws Exception {
    
        LOGGER.info("receivePaypalStatus >>>>>>>>>> 进入paypal后台支付通知");
        PrintWriter out = response.getWriter();
        try {
    
            /**
             * 获取paypal请求参数,并拼接验证参数
             */
            Enumeration<String> en = request.getParameterNames();
            String str = "cmd=_notify-validate";
            while (en.hasMoreElements()) {
    
                String paramName = en.nextElement();
                String paramValue = request.getParameter(paramName);
                //此处的编码一定要和自己的网站编码一致,不然会出现乱码,paypal回复的通知为‘INVALID’
                str = str + "&" + paramName + "=" + URLEncoder.encode(paramValue, "utf-8");
            }
            //建议在此将接受到的信息 str 记录到日志文件中以确认是否收到 IPN 信息
            LOGGER.info("paypal后台支付通知:" + str);
            /**
             * 将信息 POST 回给 PayPal 进行验证,确认回调信息的安全性
             */
            String webSrc="https://www.sandbox.paypal.com/cgi-bin/webscr";// 沙盒环境
//            String webSrc="https://www.paypal.com/cgi-bin/webscr";// 正式环境(本人是配置文件注入)
            URL u = new URL(webSrc);
            HttpURLConnection uc = (HttpURLConnection) u.openConnection();
            uc.setRequestMethod("POST");
            uc.setDoOutput(true);
            uc.setDoInput(true);
            uc.setUseCaches(false);
            //设置 HTTP 的头信息
            uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            PrintWriter pw = new PrintWriter(uc.getOutputStream());
            pw.println(str);
            pw.close();

            /**
             * 接受 PayPal 对 IPN 回发的回复信息
             */
            BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream()));
            String res = in.readLine();
            in.close();

            /**
             * 将 POST 信息分配给本地变量,可以根据您的需要添加
             */
            // 交易状态 Completed 代表交易成功
            String paymentStatus = URLEncoder.encode(request.getParameter("payment_status"), "utf-8");
            // 交易时间
            String paymentDate = request.getParameter("payment_date");
            // 交易id
            String txnId = request.getParameter("txn_id");
            // 父交易id
            String parentTxnId = request.getParameter("parent_txn_id");
            // 收款人email, 对你自己的商户
            String receiverEmail = request.getParameter("receiver_email");
            // 收款人id
            String receiverId = request.getParameter("receiver_id");
            // 付款人email
            String payerEmail = request.getParameter("payer_email");
            // 付款人id
            String payerId = request.getParameter("payer_id");
            // 交易金额
            String mcGross = request.getParameter("mc_gross");
            // 手续费
            String paymentFee = request.getParameter("payment_fee");
            // 自定义字段,我存放的订单号
            String custom = request.getParameter("custom");
            LOGGER.info("自定义参数 = " + custom);
            if (StringUtil.isBlank(res)) {
    
                res = "0";
            }
            LOGGER.info("paypal支付回调:  回调校验结果为  "+res);
            /**
             * 获取 PayPal 对回发信息的回复信息,判断刚才的通知是否为 PayPal 发出的
             * paymentStatus:Refunded 退款回调,Completed 支付完成回调
             */
            if ("VERIFIED".equalsIgnoreCase(res)) {
    
                //  订单交易成功
                if (paymentStatus.equalsIgnoreCase("Completed")) {
    
                    LOGGER.info("paypal支付回调:校验通过,准备介入自己业务");
                    try {
    
                        System.out.println("paypal支付回调:这是支付完成的回调");
                    }catch (Exception e){
    
                        e.printStackTrace();
                    }
                } else {
    
                    LOGGER.info("paypal支付回调:回调类型是 -- " + paymentStatus);
                }
            } else if ("INVALID".equalsIgnoreCase(res)) {
    
                //非法信息,可以将此记录到您的日志文件中以备调查
                LOGGER.info("paypal完成支付发送IPN通知返回状态非法,请联系管理员" + str);
                out.println("confirmError");
            } else {
    
                //处理其他错误
                LOGGER.info("paypal完成支付发送IPN通知发生其他异常,请联系管理员,请求参数:" + str);
                out.println("confirmError");
            }
        } catch (Exception e) {
    
            LOGGER.info("确认付款信息发生IO异常   " + e.getMessage());
            out.println("confirmError");
        }
        out.flush();
        out.close();
    }

爬坑重点:完成上诉类容以后,支付完成并且回调进来了,但是在" if (“VERIFIED”.equalsIgnoreCase(res)) {" 时Paypal一直返回校验不成功,后来提交工单联系Paypal的技术人员得知是因为编码格式的原因,虽然上面进行了UTF-8转码,但是在Paypal端解析时是按照设置的编码格式解码,所以需要去Paypal端设置编码格式(本人设置的UTF-8):
正式环境 https://www.paypal.com/cgi-bin/customerprofileweb?cmd=_profile-language-encoding
沙箱环境:https://www.sandbox.paypal.com/cgi-bin/customerprofileweb?cmd=_profile-language-encoding
更多编码选项中找到IPN

Paypal还有个webhook回调什么的,百度了一下,网上大多数说法是这种回调不太好用,加上业务紧急的原因,便没有深究,有使用心得的可以评论或者私信我
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_42683138/article/details/108798863

智能推荐

1024 分辨率下最快模型,字节跳动文生图开放模型 SDXL-Lightning 发布_sdxllightning下载-程序员宅基地

文章浏览阅读1k次,点赞28次,收藏25次。很高兴跟大家分享我们最新的文生图模型 —— SDXL-Lightning,它实现了前所未有的速度和质量,并且已经向社区开放。_sdxllightning下载

关于cloacked-pixel的一些总结_03-cloacked-pixel-程序员宅基地

文章浏览阅读1.5k次,点赞2次,收藏2次。前两天遇到一道lsb隐写的题目,需要用到cloacked-pixel这个脚本。工具地址下载后解压即可,这里需要注意,该脚本是基于python2的!但我电脑anaconda里面只有python3并没有很好的python基础,但借助anaconda可以轻松解决很多问题!教程如下:anaconda中添加python2但是在运行脚本时还会提示缺库(注意运行时要activate pythonXX手动切换到你所配置的python2环境下)继续使用anaconda为python2装缺少的._03-cloacked-pixel

WPF DataGrid添加右键菜单-程序员宅基地

文章浏览阅读2k次,点赞2次,收藏2次。原文http://home.cnblogs.com/group/topic/54788.html用代码添加:View Code <DataGrid.ContextMenu> <ContextMenu Name="dgmenu1" StaysOpen="true"> &..._wpf datagrid右键菜单

EB Tresos Studio离线激活方法_ebtresos离线激活-程序员宅基地

文章浏览阅读1.9k次,点赞2次,收藏6次。EB Tresos Studio离线激活方法_ebtresos离线激活

B端系统-权限管理_如何将后台管理系统b端化-程序员宅基地

文章浏览阅读95次。当然用户组是可以拓展的,部门和职位常用在内部的管理系统,如果是面向c端的系统,比如淘宝网的商家,商家自身也有一套组织架构,如采购部,销售部,客服部,后勤部,有些人拥有客服权限,有些人拥有上架权限等,这就体现了用户组的扩展性。关于数据权限的处理,常见的有两种方式,一种是在角色内完成数据权限的定义,另一种是将角色和权限分开,两种方式各有偏重。即页面的功能按钮,包括查看,新增,修改,删除,审核等,用户点击删除按钮时,后台会校验用户角色下用户的所有权限是否包含该删除权限,如果是,就可以下一步,反之提示无权限。_如何将后台管理系统b端化

音乐节拍提取一-程序员宅基地

文章浏览阅读601次。前段时间倒腾了一下音乐节拍数检测,参考下面的网上的一个测试歌曲列表做了下对比,效果还不错,基本上都是准的。Itunes LinkNameTimeArtistBPMAlbumGenreAmazon LinkLoneliest Soul03:35Grace Potter and the Nocturnals168The Lion The Bea..._提取音乐节奏

随便推点

win11实时字幕无法下载问题_微软实时字幕下载不了-程序员宅基地

文章浏览阅读776次。一直卡着的话直接去Microsoft Store下载这个试试看。_微软实时字幕下载不了

如何让谷歌Chrome地址栏恢复显示“www”和“https://”标识符_chrome 地址显示原始-程序员宅基地

文章浏览阅读1.1w次。如何让谷歌Chrome地址栏恢复显示“www”和“https://”标识符地址栏隐藏“www”和“https://”标识符  谷歌 Chrome 现在默认在所有网站地址栏中少了一些内容,“www”子域和“https://”被隐藏起来了,因为谷歌认为这些不是大多数人要关注的信息。  Chrome 的产品经理 Emily Schechter 说,他们将开始从桌面版和 Android 版的第..._chrome 地址显示原始

目标跟踪数据集整理(四)----TColor-128(Temple Color 128)_encoding color information for visual tracking: al-程序员宅基地

文章浏览阅读3.5k次。文章目录Encoding Color Information for Visual Tracking:Algorithms and Benchmark 2015官网 下载数据集(4.4G)本文认为颜色信息可以提供丰富的判别线索对于视觉推理,大多数现代视觉跟踪器限制在灰度域。(也就是主要解决输入序列是灰度版本)因此我们在算法和基准两方面做了系统的研究,证明了颜色信息可以帮助提升视觉跟踪效果。..._encoding color information for visual tracking: algorithms and benchmark

论文解读--Visual Lane Tracking and Prediction for Autonomous Vehicles-程序员宅基地

文章浏览阅读860次,点赞20次,收藏21次。我们提出了一种用于自动驾驶汽车跟踪水平道路车道标记位置的可视化方法。我们的方法是基于预测滤波的。预测步骤估计在每个新的图像帧中期望的车道标记位置。它也是基于汽车的运动学模型和嵌入式测程传感器产生的信息。使用适当准备的测试车辆获得的实验结果表明,在某些条件下,如振荡和变道,预测步骤可以显著地减少跟踪误差。因此,我们相信我们的方法应用于基于图像的控制自动驾驶汽车可以提高系统性能。

sap 标准委外和工序委外_委外加工SAP的两种典型委外处理方法-程序员宅基地

文章浏览阅读1.2k次。通常提供两种基本处理方式:外包采购和工序外包。生产外包经营方式简介生产外包作为一种全新的生产经营方式,改善了传统方式的不足,主要类型有:一.OEM:(OrignalEquipmentManufactuce->原始设备制造商)典型的OEM方式为:拥有原始设备的OEM加工方(受委托方)按照委托方的要求,用自己的设备为其加工生产产品,而后贴上委托方商标交货,整个活动中,加工方只获得加工费用,自..._工序委外加工属于什么变更类型

yolov3算法详解_2020年阿里-算法工程师面经-程序员宅基地

文章浏览阅读432次。写在前面:暑期实习从申请到拿到阿里意向书大概持续了1个月的时间,和周围其他同学比较,我的面试流程算走的比较快的了。还没有拿到意向书的朋友们也不要太着急,调整好心态好好准备(虽然内心多多少少会有些焦虑),阿里走流程算是比较快的了。希望能对求职的你有所帮助。【阿里云1面(算法实习生)】1、自我介绍、项目介绍2、死锁出现的原因以及如何避免雾夜飞鹰:死锁产生的原因及四个必要条件​zhuanlan.zhih..._yolo模型的时间复杂度