Android支付宝支払設計開発

16136 ワード

モバイル決済分野では、アリコンサルティングが発表した報告データによると、2014 Q 3では、アリペイが82.6%の市場シェアを獲得し、モバイル決済の覇者の地位がますます安定している.財付通の支払いの発力点は微信支払いと手Q支払いで、モバイル決済構造で10.0%の市場シェアを獲得し、2位にランクインした.
モバイル決済分野におけるアリペイの支配的地位は、アリペイモバイル開発プロセスを整理する必要がある.本稿の目的は、支払いプロセスを整理し、モバイルアプリケーションにアリペイの支払い機能を埋め込む方法、開発の落とし穴を指摘することです.
説明に従って、まず支付宝の支払い口座を申請する必要があります.この方面はサイトの説明に従って申請すればいいです.一般的に承認には2週間ほどかかります.
申請成功後のアカウント情報には協力者IDパートナー、売り手支付宝アカウントsellerが含まれている.id、および秘密鍵privateKeyなど.この3つは開発プロセスに使用されます.
モバイル決済統合開発パッケージを公式サイトでダウンロードします.解凍後、下に3つのフォルダが含まれていることがわかりました(英語Macシステムではファイル名が文字化けして表示されます):
  • 「商戸アクセス支付宝レジインタフェース展示基準」:支付宝ロゴの使い方を説明します.
  • 「アリペイ財布支払いインタフェース開発パッケージ2.0標準版」:クライアントとサーバ側の開発を含む支払いに使用されます.
  • 「即時入金一括返金には、密なインタフェースrefund_fastpay_by_platform_pwdがあります」:入金および一括返金に使用され、サーバ側の操作処理のみが必要です.

  • 後の2つのフォルダには、インタフェースドキュメント、アクセスと使用ルール、demoコード、バージョン更新の説明の4つの側面が含まれています.アーキテクチャ設計はまず、1つの実際のAppアプリケーションにとって、複数の支払い方式を含む可能性があるため、設計モードにおけるポリシーStrategyモードを用いて支払い機能モジュールを設計することができ、アリペイ支払いはその中の1つのポリシーとして、pay方法は支払いアルゴリズムである.支払い方法payment methodの変更に加えて、受注orderにはフォーマットが異なる場合、返金可能な場合、返金が許可されていない場合など、異なる形式がある場合があります.このような多次元可変の場合、支払いモジュールのアーキテクチャはブリッジモードに基づいています.次に、支付宝が支払う各操作手順、例えば注文番号を取得し、注文データを生成し、支払いを行い、支払い結果を取得し、異常を処理するなどの操作を状態に応じて区分することができる.このようにステータスモードを採用し、設計の柔軟性と拡張性を提供します.また、ステートマシンを設計して統一的なステータス切替管理を行うこともできます.参照コードは次のとおりです.
    
    public class PayStateMachine {
      /* all possible state of payment */
      public enum PayState { PAY_INIT, PAY_GOT_CONTEXT, PAY_UPDATED_ORDER, PAY_APPLIED_
       ID, PAY_ORDER_CREATED, PAY_SUCCEED, ERROR_OCCURRED}
         
         
      /* errors may occurred during payment */
      public enum PayError {
        PAY_GET_CONTEXT_FAIL, PAY_UPDATE_ORDER_FAIL, PAY_APPLY_ID_FAIL, PAY_FAIL
      }
         
         
      private static PayStateMachine instance;
      private PayState state;
      private IOrder order;
      private IPayment payment;
         
         
      private PayStateMachine() {
      }
         
         
      public static PayStateMachine getInstance() {
        if (instance == null) {
          instance = new PayStateMachine();
        }
         
         
        return instance;
      }
         
         
      public void initPayment(IOrder order, IPayment payment) {
        this.order = order;
        this.payment = payment;
        this.state = PayState.PAY_INIT;
      }
         
         
      public void startPay() {
        changeState(PayState.PAY_INIT);
      }
         
         
      public void changeState(PayState state) {
        onStateChanged(this.state, state);
      }
         
         
      public void reportError(PayError error, String detail) {
        LogUtil.printPayLog("the error id is:" + error + " " + detail);
        changeState(PayState.ERROR_OCCURRED);
      }
         
         
      private void onStateChanged(PayState oldState, PayState newState) {
        LogUtil.printPayLog("oid state:" + oldState + " new state:" + newState);
        this.state = newState;
         
        handlePayStateChange();
      }
         
         
      private void handlePayStateChange() {
        if (this.order == null || this.payment == null) {
          LogUtil.printPayLog("Have not initiated payment");
          return;
        }
         
         
        switch (this.state) {
          case PAY_INIT:
            order.getPayContext();
            break;
          case PAY_GOT_CONTEXT:
            order.createOrder();
            break;
          case PAY_UPDATED_ORDER:
          case PAY_APPLIED_ID:
          case PAY_ORDER_CREATED:
            payment.pay(order);
            break;
         
         
          case PAY_SUCCEED:
          case ERROR_OCCURRED:
            finishProcess();
            break;
          default:
            LogUtil.printPayLog("state is not correct!");
            finishProcess();
         }
      }
         
         
      private void finishProcess() {
        this.order = null;
        this.payment = null;
        this.state = PayState.PAY_INIT;
      }
    }
    

    最後に、受注クラス階層は、抽象ベースクラスが受注の操作フレームワークとプロセスを定義し、特定の受注データの生成がサブクラスに遅延するなど、テンプレートモードを参照して設計することができる.
    支払いプロセス本文はAndroid版について主な支払いプロセスを説明し、IOS版のプロセスは類似している.1、クライアント実現本文は操作プロセスとデータプロセスを結合し、主な実現方案を述べる.まず、受注データがOrderPayModelに格納されていると仮定します.ステップ1:Appクライアントはアプリケーションサーバにアクセスし、注文番号を生成してクライアントに戻ります.
    
    private void getOrderIdRequest() {
     JSONObject ob = new JSONObject();
     ob.put("amount", orderPayModel.getOrderPriceTotal());
            
     ob.put("productDescription", orderPayModel.getOrderName());
            
            
     ob.put("userId", orderPayModel.getUserId());
     ob.put("barCoupon", orderPayModel.getOrderId());
     ob.put("barId", orderPayModel.getBarId());
     ob.put("count", orderPayModel.getOrderNums());
     LogUtil.printPayLog("get order id request data:"
      + orderPayModel.toString());
            
            
     HttpRequestFactory.getInstance().doPostRequest(Urls.ALI_PAY_APPLY, ob,
      new AsyncHttpResponseHandler() {
            
            
       @Override
       public void onSuccess(String content) {
       super.onSuccess(content);
            
            
       LogUtil.printPayLog("get order id request is handled");
            
            
       PayNewOrderModel rm = new PayNewOrderModel();
       rm = JSON.parseObject(content, PayNewOrderModel.class);
            
            
       if (rm.getCode() != null
        && "200".equalsIgnoreCase(rm.getCode())) {
        tradeNo = rm.getResult().getTrade_no();
        LogUtil.printPayLog("succeed to get order id:"
         + tradeNo);
            
            
        orderStr = generateOrder();
        PayStateMachine.getInstance().changeState(
         PayState.PAY_APPLIED_ID);
            
            
       } else {
        PayStateMachine.getInstance().reportError(
         PayError.PAY_APPLY_ID_FAIL,
         "code is not right");
       }
       }
            
            
       @Override
       public void onFailure(Throwable error, String content) {
       PayStateMachine.getInstance().reportError(
        PayError.PAY_APPLY_ID_FAIL,
        "failed to get order id");
            
            
       };
            
            
       @Override
       public void onFinish() {
       LogUtil.LogDebug("Payment", "on get order id finish",
        null);
            
            
       };
      });
     }
    

    ステップ2:受注データを組み立てる.次のサブステップが含まれます.受注データを作成します.
    
    private String getOrderInfo(String partner, String seller) {
     String orderInfo;
            
      //      ID
      orderInfo = "partner=" + "\"" + partner + "\"";
            
            
      //        
      orderInfo += "&seller_id=" + "\"" + seller + "\"";
            
            
      //          
      orderInfo += "&out_trade_no=" + "\"" + tradeNo + "\"";
            
            
      //     
      orderInfo += "&subject=" + "\"" + orderName + "\"";
            
            
      //     
      orderInfo += "&body=" + "\"" + orderDetail + "\"";
            
            
      //     
      orderInfo += "&total_fee=" + "\"" + totalPrice + "\"";
      // orderInfo += "&total_fee=" + "\"" + "0.01" + "\"";
            
            
      //            
      orderInfo += "¬ify_url=" + "\"" + Urls.ALI_PAY_NOTIFY + "\"";
            
            
      //     ,    
      orderInfo += "&service=\"mobile.securitypay.pay\"";
            
            
      //     ,    
      orderInfo += "&payment_type=\"1\"";
            
            
      //     ,    
      orderInfo += "&_input_charset=\"utf-8\"";
            
            
      //             
      //   30  ,    ,           。
      //     :1m~15d。
      // m-  ,h-  ,d- ,1c-  (        ,  0   )。
      //            , 1.5h,    90m。
      orderInfo += "&it_b_pay=\"30m\"";
            
            
      //          ,                .
      // orderInfo += "&return_url=\"m.alipay.com\"";
      // Bill: this item must not be empty! though the api demo said it
      // can be.
      orderInfo += "&return_url=\"m.alipay.com\"";
            
            
      //        ,      ,    ,    
      // orderInfo += "&paymethod=\"expressGateway\"";
     }
            
            
     return orderInfo;
     }
    
  • 注文に対するRSA署名:demoコードにSingUtilsクラスがこの機能を実現する、すなわちSignUtilsを提供する.sign(content, RSA_PRIVATE);
  • 署名をURL符号化:javaクラスライブラリインタフェース、すなわちURLEncoderを呼び出す.Encodeで実現します.
  • 注文データと署名情報を組み合わせて、支付宝パラメータ規範に合致するデータを生成する:
  • 
    final String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + getSignType();
    
    
    

    ステップ3:サブスレッドでPayTaskのpayインタフェースを呼び出し、リクエストデータを送信する
    
    PayTask alipay = new PayTask(PayDemoActivity.this);
    //       ,      
    String result = alipay.pay(payInfo);
    

    ステップ4:支払処理結果のメッセージを受信します.支払い結果のステータスコードの意味は以下の通りです.
  • 値は「9000」で、支払いが成功したことを表します.
  • の値は「8000」で、支払い結果の確認を待つことを意味します.これは、システムの原因またはチャネルの支払いの原因による可能性があります.支払いの最終結果は、サーバ側の非同期通知に準拠する必要があります(アリペイは).
  • の値は、失敗を表す他の値です.クライアントはユーザーにプロンプトを表示する必要があります.

  • 注意事項:1、本稿で特に指摘したいのは、注文データの生成が最も問題になりやすいことです.demoコードのPayDemoActivityクラスでgetOrderInfoメソッドが定義されています.ここで、「orderInfo+="&return_url="m.alipay.com"」;”このdemoコードのコメントでは、空にできると言っていますが、実際には、空の場合、支払いに失敗します.また,失敗ステータスコードにより,具体的な原因を特定することが困難である.2、支払い結果は、アリペイサーバがクライアントに通知するほか、非同期でアプリケーションサーバに通知する.セキュリティを考慮すると、クライアントはアリペイサーバの通知に基づいて、注文更新などのビジネスロジックの処理を行うことができるが、支払うデータの入庫は、アプリケーションサーバ側が非同期通知に基づいて操作する必要がある.2、サービス側がサービス側の基本操作を実現するには、支付宝のアカウント情報(クライアントではなく安全のためにサーバに置かれている)を取得し、注文を作成し、支払い結果を非同期にコールバックし、返金を申請するなどの基本操作外を含む.また、受注の更新(受注の修正をサポートするアプリケーション)、消費コードの検証、受注記録の照会、受注の削除などの操作も含まれます.Javaプラットフォームベースのサーバスキームについて説明します.現在流行しているフレームワークの組み合わせはSpingMVC+Mybatis+Mysqlです.オーダーの作成.ユーザーが注文する場合、新しい注文(要求されたデータに注文番号情報が含まれていない)の場合は、作成し、注文番号をクライアントに返す必要があります.オーダー・クラスの例:
    
    public class PayOrder {
           
     public String tradeNo;   //    
     public String amount;   //    
     public String status;   //    
     public String statusCode;   //      ,0-   ,10-   ,4000-   ,5000-   ,6000-    ,6001-    ,7000-   
     public String orderNo;   //      
     public String productDescription;  //    
     public String payNo;   //   
     public String isRefund;   //      
     public String createTime;   //    
     public String modifyTime;   //    
     public String userId;   //  id
     public Integer id;    //  
     public String pId;    //  id
     public int buyNumber;    //      
     public int vendorId;    //  ID
    }
    tradeNo      。payNo      (   )。orderNo              。
    @RequestMapping(value = "/payorder")
    @ResponseBody
    public Map pay(HttpServletRequest request, HttpServletResponse response) {
     Map map = JsonPUtil.pToMap(request);
     Map msgMap = new HashMap();
     if (!map.isEmpty()) {
     try {
      log.info("         :" + map);
      String now = String.valueOf(System.currentTimeMillis());
      String trade_no = map.get("barId").toString() + "-" + map.get("barCoupon").toString() + "-" + map.get("count").toString() + "-" + now.substring(now.length() - 6);
        
      PayOrder alipay = new PayOrder();
      alipay.setAmount(map.get("amount").toString());
      alipay.setTradeNo(trade_no);
      alipay.setProductDescription(map.get("productDescription").toString());
      alipay.setCreateTime(now);
      alipay.setStatus("   ");
      alipay.setStatusCode("0");
      alipay.setExtInt1(Integer.parseInt(map.get("count").toString()));
      alipay.setUserId(map.get("userId").toString());
      alipay.setpId(map.get("barCoupon").toString());
      alipay.setExtInt2(Integer.parseInt(map.get("barId").toString()));
        
      int flag = alipayServiceImpl.pay(alipay);
      log.info("        :" + flag);
        
      Map m = new HashMap();
      m.put("trade_no", trade_no);
      m.put("seller", new String(Base64.encode(AlipayConfig.SELLER.getBytes())));
      m.put("partner", new String(Base64.encode(AlipayConfig.partner.getBytes())));
      m.put("privateKey", new String(Base64.encode(AlipayConfig.ios_private_key.getBytes())));
        
      if (flag > 0)
      msgMap = ResponseMessageUtil.respMsg(Constance.BASE_SUCCESS_CODE, "success", m);
      else
      msgMap = ResponseMessageUtil.respMsg(Constance.BASE_SERVER_WRONG_CODE, "fail");
     } catch (Exception e) {
      e.printStackTrace();
      msgMap = ResponseMessageUtil.respMsg(Constance.BASE_SERVER_WRONG_CODE, "fail");
      log.error("       ", e);
     }
     } else {
     log.info("       ");
     msgMap = ResponseMessageUtil.respMsg(Constance.ILLEGAL_OPERATE, "fail");
     }
     return msgMap;
    }
    

    アリペイサーバーはAppサーバーにコールバックし、支払い結果を通知します.Appサーバは、対応するデータを入庫した後、アリペイサーバ「success」or「fail」に通知します.
    
    @RequestMapping(value = "/payOver")
     @ResponseBody
     public String payOver(HttpServletRequest request, HttpServletResponse response) {
     Map map = JsonPUtil.buildMap(request);
     String result_str = "fail";
     if (!map.isEmpty()) {
      if (AlipayUtils.checkAlipay(map, false) > 0) {//        
      try {
       log.info("             :" + map);
       String now = String.valueOf(System.currentTimeMillis());
       String status = map.get("trade_status").toString();
       PayOrder alipay = new PayOrder();
       alipay.setTradeNo(String.valueOf(map.get("out_trade_no")));
       log.info("    :" + status);
       if (Constance.ALIPAY_SUCCESS_CODE.equals(status) || Constance.ALIPAY_FINISHED_CODE.equals(status)) {//     
       List ali = alipayServiceImpl.search(alipay);
       if (ali.size() == 1 && (ali.get(0).getPayNo() == null || ali.get(0).getPayNo().equals(""))) {//      
        Alipay pay = new Alipay();
        pay.setTradeNo(String.valueOf(map.get("out_trade_no")));
        pay.setStatus("   ");
        pay.setStatusCode("10");
        pay.setIsRefund("0");
        pay.setModifyTime(String.valueOf(System.currentTimeMillis()));
        pay.setPayNo(new String(Base64.encode(now.substring(now.length() - 10).getBytes())));
        pay.setOrderNo(String.valueOf(map.get("trade_no")));
        int flag = alipayServiceImpl.payOver(pay);
        log.info("      " + map);
        if (flag > 0)
        result_str = "success";
       }
       } else {
       return result_str;
       }
      } catch (Exception e) {
       e.printStackTrace();
       log.error("          ", e);
       return result_str;
      }
      }
     }
     return result_str;
     }

    以上、Android支付宝の支払い設計と開発案に基づいて、Androidソフトウェアのプログラミングを学ぶのに役立つことを望んでいます.