Ping++ 支付接口对接

本文介绍如何使用Ping++ SDK实现支付功能,并详细解释了Webhooks通知的验证过程,确保交易信息的安全可靠。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、请求charge对象

  1. package com.bra.modules.util.pingplusplus;  
  2.   
  3. import com.bra.common.utils.SystemPath;  
  4. import com.pingplusplus.Pingpp;  
  5. import org.springframework.stereotype.Service;  
  6.   
  7. import java.io.File;  
  8.   
  9. /** 
  10.  * Created by Afon on 16/4/26. 
  11.  */  
  12. @Service  
  13. public class PingPlusPlusService {  
  14.       
  15.     /** 
  16.      * Pingpp 管理平台对应的 API Key 
  17.      */  
  18.     private final static String apiKey = "";  
  19.   
  20.   
  21.     /** 
  22.      * Pingpp 管理平台对应的应用 ID 
  23.      */  
  24.     private final static String appId = "";  
  25.     /** 
  26.      * 你生成的私钥路径 
  27.      */  
  28.     private final static String privateKeyFilePath = File.separator+SystemPath.getClassPath()+"res"+ File.separator+"rsa_private_key.pem";  
  29.   
  30.     public static String charge(String orderNo,int amount,String subject,String body,String channel,String clientIP){  
  31.   
  32.         // 设置 API Key  
  33.         Pingpp.apiKey = apiKey;  
  34.   
  35.         // 设置私钥路径,用于请求签名  
  36.         Pingpp.privateKeyPath = privateKeyFilePath;  
  37.         PingPlusCharge charge=new PingPlusCharge(appId);  
  38.         String chargeString=charge.createCharge(orderNo,amount,subject,body,channel,clientIP);  
  39.         return chargeString;  
  40.     }  
  41. }  

二、生成charge 对象

  1. package com.bra.modules.util.pingplusplus;  
  2.   
  3. import com.pingplusplus.exception.PingppException;  
  4. import com.pingplusplus.model.Charge;  
  5.   
  6. import java.util.Calendar;  
  7. import java.util.HashMap;  
  8. import java.util.Map;  
  9.   
  10. /** 
  11.  * Created by Afon on 16/4/26. 
  12.  */  
  13. public class PingPlusCharge {  
  14.   
  15.     private String appId;  
  16.   
  17.   
  18.     PingPlusCharge(String appId) {  
  19.         this.appId = appId;  
  20.     }  
  21.   
  22.     public String createCharge(String orderNo, int amount, String subject, String body, String channel, String clientIP) {  
  23.   
  24.         /** 
  25.          * 或者直接设置私钥内容 
  26.          Pingpp.privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" + 
  27.          "... 私钥内容字符串 ...\n" + 
  28.          "-----END RSA PRIVATE KEY-----\n"; 
  29.          */  
  30.         Map<String, Object> chargeMap = new HashMap<String, Object>();  
  31.         chargeMap.put("amount", amount);  
  32.         chargeMap.put("currency", "cny");  
  33.         chargeMap.put("subject", subject);  
  34.         chargeMap.put("body", body);  
  35.         chargeMap.put("order_no", orderNo);  
  36.         chargeMap.put("channel", channel);  
  37.   
  38.         Calendar cal = Calendar.getInstance();  
  39.         cal.add(Calendar.MINUTE, 15);//15分钟失效  
  40.         long timestamp = cal.getTimeInMillis()/ 1000L;  
  41.         chargeMap.put("time_expire", timestamp);  
  42.   
  43.         chargeMap.put("client_ip", clientIP); // 客户端 ip 地址(ipv4)  
  44.         Map<String, String> app = new HashMap<String, String>();  
  45.         app.put("id", appId);  
  46.         chargeMap.put("app", app);  
  47.         String chargeString = null;  
  48.         try {  
  49.             //发起交易请求  
  50.             Charge charge = Charge.create(chargeMap);  
  51.             // 传到客户端请先转成字符串 .toString(), 调该方法,会自动转成正确的 JSON 字符串  
  52.             chargeString = charge.toString();  
  53.         } catch (PingppException e) {  
  54.             e.printStackTrace();  
  55.         }  
  56.         return chargeString;  
  57.     }  
  58. }   

三、webhook

  1. @RequestMapping(value = "webhooks")  
  2.    @ResponseBody  
  3.    public void webhooks ( HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException  {  
  4.        /*System.out.println("ping++ webhooks");*/  
  5.        request.setCharacterEncoding("UTF8");  
  6.        //获取头部所有信息  
  7.        Enumeration headerNames = request.getHeaderNames();  
  8.        String signature=null;  
  9.        while (headerNames.hasMoreElements()) {  
  10.            String key = (String) headerNames.nextElement();  
  11.            String value = request.getHeader(key);  
  12.            if("x-pingplusplus-signature".equals(key)){  
  13.                signature=value;  
  14.            }  
  15.        }  
  16.        /*System.out.println("signature"+signature);*/  
  17.        // 获得 http body 内容  
  18.        StringBuffer eventJson=new StringBuffer();  
  19.       BufferedReader reader= null;  
  20.        try {  
  21.            reader = request.getReader();  
  22.            do{  
  23.                eventJson.append(reader.readLine());  
  24.            }while(reader.read()!=-1);  
  25.        } catch (IOException e) {  
  26.            e.printStackTrace();  
  27.        }  
  28.        reader.close();  
  29.        JSONObject event=JSON.parseObject(eventJson.toString());  
  30.        boolean verifyRS=false;  
  31.        try {  
  32.            PublicKey publicKey= WebhooksVerifyService.getPubKey();  
  33.          /*  System.out.println(publicKey);*/  
  34.            verifyRS=WebhooksVerifyService.verifyData(eventJson.toString(),signature,publicKey);  
  35.        } catch (Exception e) {  
  36.            e.printStackTrace();  
  37.        }  
  38.   
  39.        if(verifyRS) {  
  40.            /*System.out.println("签名验证成功");*/  
  41.            if ("charge.succeeded".equals(event.get("type"))) {  
  42.                JSONObject data = JSON.parseObject(event.get("data").toString());  
  43.                JSONObject object = JSON.parseObject(data.get("object").toString());  
  44.                String orderId = (String) object.get("order_no");  
  45.                /*System.out.println("orderId:"+orderId);*/  
  46.                String channel = (String) object.get("channel");  
  47.                String payType = null;  
  48.                int amountFen = (int) object.get("amount");  
  49.                Double amountYuan = amountFen * 1.0 / 100;//ping++扣款,精确到分,而数据库精确到元  
  50.                Double weiXinInput = null;  
  51.                Double aliPayInput = null;  
  52.                Double bankCardInput = null;  
  53.   
  54.                if ("wx".equals(channel)) {  
  55.                    payType = "4";//支付类型(1:储值卡,2:现金,3:银行卡,4:微信,5:支付宝,6:优惠券,7:打白条;8:多方式付款;9:微信个人,10:支付宝(个人))  
  56.                    weiXinInput = amountYuan;  
  57.                } else if ("alipay".equals(channel)) {  
  58.                    payType = "5";  
  59.                    aliPayInput = amountYuan;  
  60.                } else if ("upacp".equals(channel) || "upacp_wap".equals(channel) || "upacp_pc".equals(channel)) {  
  61.                    payType = "3";  
  62.                    bankCardInput = amountYuan;  
  63.                }  
  64.                Double couponInput;  
  65.                ReserveVenueCons order = reserveAppVenueConsService.get(orderId);  
  66.   
  67.                if (order != null) {  
  68.                    Double orderPrice = order.getShouldPrice();  
  69.                    couponInput = orderPrice - amountYuan;//订单金额-ping++扣款 等于优惠金额  
  70.                    Boolean bool = reserveAppVenueConsService.saveSettlement(order, payType, amountYuan,  
  71.                            0.0, bankCardInput, weiXinInput, aliPayInput, couponInput);  
  72.                    if (bool) {  
  73.                      /*  System.out.println("订单结算成功");*/  
  74.                        response.setStatus(200);  
  75.                        //return "订单结算成功";  
  76.                    } else {  
  77.                       /* System.out.println("订单结算失败");*/  
  78.                        //return "订单结算失败";  
  79.                        response.setStatus(500);  
  80.                    }  
  81.                } else {  
  82.                   /* System.out.println("该订单不存在");*/  
  83.                    //return "该订单不存在";  
  84.                    response.setStatus(500);  
  85.                }  
  86.            }  
  87.        }else{  
  88.            /*System.out.println("签名验证失败");*/  
  89.            //return "签名验证失败";  
  90.            response.setStatus(500);  
  91.        }  
  92.    }  

四、WebhooksVerifyService

 

  1. package com.bra.modules.util.pingplusplus;  
  2.   
  3. import com.bra.common.utils.SystemPath;  
  4. import org.apache.commons.codec.binary.Base64;  
  5.   
  6. import java.io.*;  
  7. import java.security.*;  
  8. import java.security.spec.X509EncodedKeySpec;  
  9.   
  10. /** 
  11.  * Created by sunkai on 15/5/19. webhooks 验证签名示例 
  12.  * 
  13.  * 该实例演示如何对 Ping++ webhooks 通知进行验证。 
  14.  * 验证是为了让开发者确认该通知来自 Ping++ ,防止恶意伪造通知。用户如果有别的验证机制,可以不进行验证签名。 
  15.  * 
  16.  * 验证签名需要 签名、公钥、验证信息,该实例采用文件存储方式进行演示。 
  17.  * 实际项目中,需要用户从异步通知的 HTTP header 中读取签名,从 HTTP body 中读取验证信息。公钥的存储方式也需要用户自行设定。 
  18.  * 
  19.  *  该实例仅供演示如何验证签名,请务必不要直接 copy 到实际项目中使用。 
  20.  * 
  21.  */  
  22. public class WebhooksVerifyService {  
  23.   
  24.     private static String pubKeyPath = File.separator+ SystemPath.getClassPath()+"res"+ File.separator+"pingpp_public_key.pem";  
  25.     private static String eventPath = File.separator+SystemPath.getClassPath()+"res"+ File.separator+"webhooks_raw_post_data.json";  
  26.     private static String signPath = File.separator+SystemPath.getClassPath()+"res"+ File.separator+"signature.txt";  
  27.   
  28.     /** 
  29.      * 验证 webhooks 签名,仅供参考 
  30.      * @param args 
  31.      * @throws Exception 
  32.      */  
  33.     public static void main(String[] args) throws Exception {  
  34.         runDemos();  
  35.     }  
  36.   
  37.     public static void runDemos() throws Exception {  
  38.         // 该数据请从 request 中获取原始 POST 请求数据, 以下仅作为示例  
  39.         String webhooksRawPostData = getStringFromFile(eventPath);  
  40.         System.out.println("------- POST 原始数据 -------");  
  41.         System.out.println(webhooksRawPostData);  
  42.         // 签名数据请从 request 的 header 中获取, key 为 X-Pingplusplus-Signature (请忽略大小写, 建议自己做格式化)  
  43.         String signature = getStringFromFile(signPath);  
  44.         System.out.println("------- 签名 -------");  
  45.         System.out.println(signature);  
  46.         boolean result = verifyData(webhooksRawPostData, signature, getPubKey());  
  47.         System.out.println("验签结果:" + (result ? "通过" : "失败"));  
  48.     }  
  49.   
  50.     /** 
  51.      * 读取文件, 部署 web 程序的时候, 签名和验签内容需要从 request 中获得 
  52.      * @param filePath 
  53.      * @return 
  54.      * @throws Exception 
  55.      */  
  56.     public static String getStringFromFile(String filePath) throws Exception {  
  57.         FileInputStream in = new FileInputStream(filePath);  
  58.         InputStreamReader inReader = new InputStreamReader(in, "UTF-8");  
  59.         BufferedReader bf = new BufferedReader(inReader);  
  60.         StringBuilder sb = new StringBuilder();  
  61.         String line;  
  62.         do {  
  63.             line = bf.readLine();  
  64.             if (line != null) {  
  65.                 if (sb.length() != 0) {  
  66.                     sb.append("\n");  
  67.                 }  
  68.                 sb.append(line);  
  69.             }  
  70.         } while (line != null);  
  71.   
  72.         return sb.toString();  
  73.     }  
  74.   
  75.     /** 
  76.      * 获得公钥 
  77.      * @return 
  78.      * @throws Exception 
  79.      */  
  80.     public static PublicKey getPubKey() throws Exception {  
  81.         String pubKeyString = getStringFromFile(pubKeyPath);  
  82.         pubKeyString = pubKeyString.replaceAll("(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)", "");  
  83.         byte[] keyBytes = Base64.decodeBase64(pubKeyString);  
  84.   
  85.         // generate public key  
  86.         X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);  
  87.         KeyFactory keyFactory = KeyFactory.getInstance("RSA");  
  88.         PublicKey publicKey = keyFactory.generatePublic(spec);  
  89.         return publicKey;  
  90.     }  
  91.   
  92.     /** 
  93.      * 验证签名 
  94.      * @param dataString 
  95.      * @param signatureString 
  96.      * @param publicKey 
  97.      * @return 
  98.      * @throws NoSuchAlgorithmException 
  99.      * @throws InvalidKeyException 
  100.      * @throws SignatureException 
  101.      */  
  102.     public static boolean verifyData(String dataString, String signatureString, PublicKey publicKey)  
  103.             throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {  
  104.         byte[] signatureBytes = Base64.decodeBase64(signatureString);  
  105.         Signature signature = Signature.getInstance("SHA256withRSA");  
  106.         signature.initVerify(publicKey);  
  107.         signature.update(dataString.getBytes("UTF-8"));  
  108.         return signature.verify(signatureBytes);  
  109.     }  
  110.   
  111. }  

转载于:https://my.oschina.net/rightemperor/blog/886562

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值