超詳細的java接入ping++支付(聚合支付)

package com.hecross.common.pay;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import com.hecross.common.crypt.Base64;
import com.pingplusplus.Pingpp;
import com.pingplusplus.exception.APIConnectionException;
import com.pingplusplus.exception.APIException;
import com.pingplusplus.exception.AuthenticationException;
import com.pingplusplus.exception.ChannelException;
import com.pingplusplus.exception.InvalidRequestException;
import com.pingplusplus.exception.RateLimitException;
import com.pingplusplus.model.Charge;
import com.pingplusplus.model.Refund;

/**
 * 支付工具
 *
 * @author zqli
 *
 */
public class PayUtil {
   public static String REFUNDSUCCESS = "pending";
   /**
    * Pingpp 管理平臺對應的 API Keyapi_key 獲取方式:登錄 [Dashboard](https://dashboard.pingxx.com)->點擊管理平臺右上角公司名稱->開發信息-> Secret
    * Key
    */
   // private final static String apiKey = "sk_test_unXbjTPi9m5GXLWvfD8Wb140";
   private final static String apiKey = "sk_live_zzPu9GfPqjTKaL";
   private final static String apiKeytest = "sk_live_b9Ge1CPqDWfD";
   /**
    * Pingpp 管理平臺對應的應用 IDapp_id 獲取方式:登錄 [Dashboard](https://dashboard.pingxx.com)->點擊你創建的應用->應用首頁->應用 ID(App ID)
    */
   private final static String appId = "app_j9GCi118azv";
   private final static String appIdceshi = "app_uvrPO4fnD";

   /**
    * 設置請求籤名密鑰,密鑰對需要你自己用 openssl 工具生成,如何生成可以參考幫助中心:https://help.pingxx.com/article/123161    * 生成密鑰後,需要在代碼中設置請求籤名的私鑰(rsa_private_key.pem); 然後登錄
    * [Dashboard](https://dashboard.pingxx.com)->點擊右上角公司名稱->開發信息->商戶公鑰(用於商戶身份驗證) 將你的公鑰複製粘貼進去並且保存->先啓用 Test
    * 模式進行測試->測試通過後啓用 Live 模式
    */


   private final static String pubKey = "-----BEGIN PUBLIC KEY-----\n"
         + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0pyjbt81nCR+HqEWBkT6\n"
         + "DKz2amX6G/JJ7jX5IzxGmA2CoaEhgwA0IDZU9ft8TyTQK/BbmWasAFoZN2LV7u83\n"
         + "eexWcb6gKgSr/PPblAmERgNrJ4PQqXnn+XFHGqmRrSaH+C2maNOtd4Sx6BYhSDKS\n"
         + "gH7DbRGg2LyiLpc2C8qASj3/1kT8VVqqbIKOTA5N45YFfsAF\n"
         + "dmIyaX6nimqtE2M6pknwQUtt8QtXht4+7Nd/op/GwftW6+80nF3bLGcj3\n"
         + "fcNAM35zSqHptFUTUOjg5VknF5tP7FN6NO+h8GYUHmgwewUWKEUbVKJ6\n" + "gwIDAQAB\n"
         + "-----END PUBLIC KEY-----\n";
   private final static String pubKeyTest = "-----BEGIN PUBLIC KEY-----\n" +
         "MIIBIjANBgkqhkiG9w0BAQEFAAOCgKCAQEApissF5ACwGRgrA7poo2F\n" +
         "kDsAX3LAzs/8AXPQV8CAhGmMzYZGBx+NcurQdpB5j124ZUWvl8raAXnk\n" +
         "nIyMe9OQZ3y0P7qCq//G+rp7SDqJV5hzuWChZSOFNs8wRtMGIfgLRKiO\n" +
         "dEV4vQtsm9oDa4YMzePJDdHWCqQ7tswcnGdoShmsGbb+m+PVMC3eviQHb\n" +
         "8EHl0jXH2x//bI1CQRAFbVd+mgwZj1TZPV/3AttjNGvKb9oYDZ\n" +
         "vQMtbh2KzNsYxDQeQjRvNof+XASrDBUQahCQ+bGVrRh3AKEAA1fKhkTDu8XaK5FD\n" +
         "1QIDAQAB\n" +
         "-----END PUBLIC KEY-----\n";
   private final static String privateKey = "-----BEGIN RSA PRIVATE KEY-----\n"
         + "MIICXgIBAAKBgQDa4iPHQoKjtoDkZ6bXRKtrLoMvCL3vSWqqsR7keS3RZNgaqMDC\n"
         + "AGue8Lg3a6FGsp2S+B5RQ42vtyjxRwc3+oZg3P+KjEUMk2YL8BKaQIDAQAB\n"
         + "AoGBAJT127WK3Q9/b76Bj/jmoeZilCKZR3GmvDIIMmb41SaxA6U4/V3KHXPgjO4i\n"
         + "kHJlsnlH5JIXbgy4iB18UPrHWVatwx9Y2vWqPvt0wFfJIQlUbM5t2ChlFe9OSB6a\n"
         + "U+y/2CNDHuWBWDXGF5iKZZcVsUvp3laaVFhUZhA9X+oeE0W1AkEA9747Ukc0Zs7/\n"
         + "KlFyGIXrZz9SDhdyMDvPf0BwP1yxq2Q7UL0y1n4yMcsWxoyOCSQb17GQqWuKk2i6\n"
         + "VSE5geLRbwJBAOItrIjL2DE6kjyB93ePubKZgJuwo4bm+E6NPBjPfdd\n"
         + "h4c/z4EHJwhG58O/4bSWRCmjb1EWWt41hacCQQDab2hui0mwvCJPdbBb3vhH+JSo\n"
         + "yBNuY834LSDLPTeKHr4N2kdQ+SxAhhfY+6wssHdLs7HaABzURAkAH\n"
         + "9HVKBmlfKeOx3WCCrU659BFEw2lQ8rNtyHl9SAlOfZ6ZCdSHG7oFjr/8mMTNrLjA\n"
         + "EMKeeF6DXGUw4+lkQVunAkEA+E8NAw/EQoF/xpn7vKORu5Lg7SYcQ\n"
         + "6OzDoN1iua0RBjnjC/Qx2UhS2/ox9rhjhgd5oDxc0iXrag==\n" + "-----END RSA PRIVATE KEY-----\n";
  
   private static PayUtil instance = new PayUtil();

   private PayUtil() {
   }

   public static PayUtil getInstance() {
      return instance;
   }

   {
      // 設置 API Key
//    Pingpp.apiKey = apiKey;
      Pingpp.apiKey = apiKeytest;
      // 設置私鑰路徑,用於請求籤名
      // Pingpp.privateKeyPath = privateKeyFilePath;
      Pingpp.privateKey = privateKey;
//    Pingpp.privateKey = privateKeytest;
   }

   /**
    * /** 發起支付 map 裏面參數的具體說明請參考:https://www.pingxx.com/api#api-c-new
    *
    * @param amount 訂單總金額, 人民幣單位:分(如訂單總金額爲 1 元,此處請填 100    * @param subject 商品描述
    * @param body 商品詳細信息
    * @param orderNo 訂單編號
    * @param channel 渠道 alipay wx
    * @param ip 客戶端IP
    * @param extra 可擴展字段 渠道參數詳情ping++查看
    * @param initialMetadata 可擴展字段 用戶回傳值定義
    * @return 返回客戶端 該訂單 請求信息
    */
   // 返回charge數據
   // {
   // "id": "ch_a5OinLGyzzjLXPSOy9rPKKiL",
   // "object": "charge",
   // "created": 1458186221,
   // "livemode": true,
   // "paid": false,
   // "refunded": false,
   // "app": "app_1Gqj58ynP0mHeX1q",
   // "channel": "alipay",
   // "order_no": "123456789",
   // "client_ip": "127.0.0.1",
   // "amount": 100,
   // "amount_settle": 100,
   // "currency": "cny",
   // "subject": "Your Subject",
   // "body": "Your Body",
   // "extra": {},
   // "time_paid": null,
   // "time_expire": 1458272621,
   // "time_settle": null,
   // "transaction_no": null,
   // "refunds": {
   // "object": "list",
   // "url": "/v1/charges/ch_a5OinLGyzzjLXPSOy9rPKKiL/refunds",
   // "has_more": false,
   // "data": []
   // },
   // "amount_refunded": 0,
   // "failure_code": null,
   // "failure_msg": null,
   // "metadata": {},
   // "credential": {
   // "object": "credential",
   // "alipay": {
   // "orderInfo":
   // "service=\"mobile.securitypay.pay\"&_input_charset=\"utf-8\"&notify_url=\"https%3A%2F%2Fapi.pingxx.com%2Fnotify%2Fcharges%2Fch_a5OinLGyzzjLXPSOy9rPKKiL\"&partner=\"2008010319263982\"&out_trade_no=\"123456789\"&subject=\"Your
   // Subject\"&body=\"Your
   // Body\"&total_fee=\"0.10\"&payment_type=\"1\"&seller_id=\"2088020116983982\"&it_b_pay=\"2016-03-18
   // 11:43:41\"&sign=\"ODRJPReSwsH8om5fGTqvhia9453k4eUaaGMJTLMTnEYbBuceMyTathvKtdnUpsP6Q5%2F5jcEV887EdtBWi4tuMFHPQmm4dz1nG6b4Blafi6v2tvKaf8b0RiQTOycU4SxigugKoyfeR6E4AGA6uIzWUBRpkq%2BZf65eqT0qe712BJ0%3D\"&sign_type=\"RSA\""
   // }
   // },
   // "description": "Your Description"
   // }
   public Charge createCharge(int amount, String subject, String body, String channel, String ip, String orderNo,
                        Map<String, Object> extra, Map<String, Object> initialMetadata) {
      Charge charge = null;
      Map<String, Object> chargeMap = new HashMap<String, Object>();
      chargeMap.put("amount", amount);// 訂單總金額, 人民幣單位:分(如訂單總金額爲 1 元,此處請填 100      chargeMap.put("currency", "cny");
      chargeMap.put("subject", subject);
      chargeMap.put("body", body);
      // String orderNo = new Date().getTime() + PayUtil.randomString(7);
      chargeMap.put("order_no", orderNo);// 推薦使用 8-20 位,要求數字或字母,不允許其他字符
      chargeMap.put("channel", channel);// 支付使用的第三方支付渠道取值,請參考:https://www.pingxx.com/api#api-c-new
      chargeMap.put("client_ip", ip); // 發起支付請求客戶端的 IP 地址,格式爲 IPV4,如: 127.0.0.1
      Map<String, String> app = new HashMap<String, String>();
      app.put("id", appId);
      chargeMap.put("app", app);
      if (extra == null)
         extra = new HashMap<String, Object>();
      chargeMap.put("extra", extra);

      if (initialMetadata == null)
         initialMetadata = new HashMap<String, Object>();
      // initialMetadata.put("color", "red");

      chargeMap.put("metadata", initialMetadata);
      try {
         // 發起交易請求
         charge = Charge.create(chargeMap);
         // 傳到客戶端請先轉成字符串 .toString(), 調該方法,會自動轉成正確的 JSON 字符串
         String chargeString = charge.toString();
         System.out.println(chargeString);
      } catch (APIConnectionException e) {
         e.printStackTrace();
      } catch (ChannelException e) {
         e.printStackTrace();
      } catch (RateLimitException e) {
         e.printStackTrace();
      } catch (AuthenticationException e) {
         e.printStackTrace();
      } catch (APIException e) {
         e.printStackTrace();
      } catch (InvalidRequestException e) {
         e.printStackTrace();
      }
      return charge;
   }

   public Charge createChargeForWx(int amount, String subject, String body, String channel, String ip, String orderNo,
                           Map<String, Object> extra, Map<String, Object> initialMetadata) {
      Charge charge = null;
      Map<String, Object> chargeMap = new HashMap<String, Object>();
      chargeMap.put("amount", amount);// 訂單總金額, 人民幣單位:分(如訂單總金額爲 1 元,此處請填 100      chargeMap.put("currency", "cny");
      chargeMap.put("subject", subject);
      chargeMap.put("body", body);
      // String orderNo = new Date().getTime() + PayUtil.randomString(7);
      chargeMap.put("order_no", orderNo);// 推薦使用 8-20 位,要求數字或字母,不允許其他字符
      chargeMap.put("channel", channel);// 支付使用的第三方支付渠道取值,請參考:https://www.pingxx.com/api#api-c-new
      chargeMap.put("client_ip", ip); // 發起支付請求客戶端的 IP 地址,格式爲 IPV4,如: 127.0.0.1
      Map<String, String> app = new HashMap<String, String>();
      app.put("id", appIdceshi);
      chargeMap.put("app", app);
      if (extra == null)
         extra = new HashMap<String, Object>();
      chargeMap.put("extra", extra);

      if (initialMetadata == null)
         initialMetadata = new HashMap<String, Object>();

      chargeMap.put("metadata", initialMetadata);
      try {
         // 發起交易請求
         charge = Charge.create(chargeMap);
         System.out.println(charge);
         // 傳到客戶端請先轉成字符串 .toString(), 調該方法,會自動轉成正確的 JSON 字符串
         String chargeString = charge.toString();
         System.out.println(chargeString);
      } catch (APIConnectionException e) {
         e.printStackTrace();
      } catch (ChannelException e) {
         e.printStackTrace();
      } catch (RateLimitException e) {
         e.printStackTrace();
      } catch (AuthenticationException e) {
         e.printStackTrace();
      } catch (APIException e) {
         e.printStackTrace();
      } catch (InvalidRequestException e) {
         e.printStackTrace();
      }
      return charge;
   }

   /**
    * 退款
    *
    * 創建退款,需要先獲得 charge ,然後調用 charge.getRefunds().create(); 參數具體說明參考:https://www.pingxx.com/api#api-r-new
    * 可以一次退款,也可以分批退款。
    *
    * @param amount 退款的金額, 單位爲對應幣種的最小貨幣單位,例如:人民幣爲分(如退款金額爲 1 元,此處請填 100)。必須小於等於可退款金額,默認爲全額退款
    * @param chargeId 交易流水號
    * @param description 退款描述
    * @return Refund 退款json信息
    */
   // {
   // "id": "re_y1u944PmfnrTHyvnL0nD0iD1",
   // "object": "refund",
   // "order_no": "y1u944PmfnrTHyvnL0nD0iD1",
   // "amount": 9,
   // "created": 1409634160,
   // "succeed": true,
   // "status": "succeeded",
   // "time_succeed": 1409634192,
   // "description": "Refund Description",
   // "failure_code": null,
   // "failure_msg": null,
   // "metadata": {},
   // "charge": "ch_L8qn10mLmr1GS8e5OODmHaL4",
   // "charge_order_no": "123456789",
   // "transaction_no": "2004450349201512090096425284"
   // }
   public Refund refund(Integer amount, String chargeId, String description) {
      if (chargeId == null) {
         return null;
      }
      Refund refund = null;
      Map<String, Object> params = new HashMap<String, Object>();
      params.put("description", description);
      params.put("amount", amount);// 退款的金額, 單位爲對應幣種的最小貨幣單位,例如:人民幣爲分(如退款金額爲 1 元,此處請填 100)。必須小於等於可退款金額,默認爲全額退款

      try {
         refund = Refund.create(chargeId, params);
         System.out.println(refund);
      } catch (AuthenticationException e) {
         e.printStackTrace();
      } catch (InvalidRequestException e) {
         e.printStackTrace();
      } catch (APIConnectionException e) {
         e.printStackTrace();
      } catch (APIException e) {
         e.printStackTrace();
      } catch (ChannelException e) {
         e.printStackTrace();
      } catch (RateLimitException e) {
         e.printStackTrace();
      }
      return refund;
   }

   /**
    * 查詢退款
    *
    * 根據 Id 查詢退款記錄。需要傳遞 charge。 參考文檔:https://www.pingxx.com/api#api-r-inquiry
    *
    * @param refundid 退款ID
    * @param chargeId 交易流水號
    * @return 退款信息json
    */
   public String retrieve(String refundid, String chargeId) {
      if (chargeId == null) {
         return null;
      }
      Refund refund = null;
      try {
         refund = Refund.retrieve(chargeId, refundid);
         System.out.println(refund);
      } catch (AuthenticationException e) {
         e.printStackTrace();
      } catch (InvalidRequestException e) {
         e.printStackTrace();
      } catch (APIConnectionException e) {
         e.printStackTrace();
      } catch (APIException e) {
         e.printStackTrace();
      } catch (ChannelException e) {
         e.printStackTrace();
      } catch (RateLimitException e) {
         e.printStackTrace();
      }
      return refund.toString();
   }

   /**
    * 獲得公鑰
    *
    * @return
    * @throws Exception
    */
   public PublicKey getPubKey() throws Exception {
//    String pubKeyString = pubKey.replaceAll("(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)", "");
      String pubKeyString = pubKeyTest.replaceAll("(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)", "");
      byte[] keyBytes = Base64.decode(pubKeyString);

      // generate public key
      X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      PublicKey publicKey = keyFactory.generatePublic(spec);
      return publicKey;
   }

   /**
    * 驗證簽名
    *
    * @param dataString
    * @param signatureString
    * @param publicKey
    * @return
    * @throws NoSuchAlgorithmException
    * @throws InvalidKeyException
    * @throws SignatureException
    */
   public boolean verifyData(String dataString, String signatureString, PublicKey publicKey)
         throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
      byte[] signatureBytes = Base64.decode(signatureString);
      Signature signature = Signature.getInstance("SHA256withRSA");
      signature.initVerify(publicKey);
      signature.update(dataString.getBytes("UTF-8"));
      return signature.verify(signatureBytes);
   }

   private static SecureRandom random = new SecureRandom();

   public static String randomString(int length) {
      String str = new BigInteger(130, random).toString(32);
      return str.substring(0, length);
   }

   public static int currentTimeSeconds() {
      return (int) (System.currentTimeMillis() / 1000);
   }

   public static void main(String[] args) {
   }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章