위 챗 결제 의 공중번호 지불(자바 실현)

최근 2 주 동안 위 챗 인 터 페 이 스 를 이용 하여 위 챗 을 사용 하여 지불 하 는 수 요 를 실현 했다.공중 번호 지불 과 스 캔 결제 두 가지 방식 을 포함한다.위 챗 문 서 를 비교적 간략하게 썼 기 때문에 현 재 는 위 챗 인 터 페 이 스 를 이용 하여 지불 절 차 를 기록 하고 공유 할 것 이다.
본 고 는 공중 번호 지불 의 실현 절 차 를 소개 하고 자 한다.즉,위 챗 사용자 가 공중 번호 에서 링크 를 클릭 하여 상품 h5 페이지 에 들 어가 고 상품 을 선택 한 후에 지불 단 추 를 클릭 한 후에 위 챗 결제 페이지 를 팝 업 하고 지불 비밀 번 호 를 입력 하 며 지불 에 성공 한 후에 모든 상품 페이지 로 넘 어 가 는 전체 과정 이다.위 챗 스 캔 결 제 는 후속 글 을 참조 하 시기 바 랍 니 다.
1.우선,상 가 는 위 챗 공중 번호,위 챗 상점 번호 와 위 챗 결제 권한 을 신청 해 야 합 니 다.개발 과정 에서 공중 번호 와 상점 플랫폼 을 참조 하여 다음 과 같은 매개 변 수 를 제공 해 야 한다.
① appid:공중 번호 id,위 챗 공중 번호 C 개발 C 기본 설정 에 로그 인하 여 얻 을 수 있 습 니 다.
② mch_id:수금 업 체 상점 번호;
③ APP_SECRET:제3자 유일한 증빙 비밀번호;
④ key:수금 업 체 백 엔 드 를 설정 하고 위 챗 업 체 플랫폼 C 계 정 에 로그 인하 여 C 안전 설정 Capi 안전,32 비트 key 값 을 설정 합 니 다.
2.위 챗 공식 번호 에 로그 인하 여 관련 설정 을 개발 합 니 다.
① 사용자 기본 정보 획득(주로 openid)권한 설정:위 챗 퍼 블 릭 플랫폼 C 개발 C 인터페이스 권한 C 웹 페이지 권한 부여 C 웹 페이지 권한 부여 도 메 인 이름(IP 주 소 를 받 지 않 고 ICP 등록 검증 을 통 해 http 없 음):
这里写图片描述  
② 지불 테스트 디 렉 터 리 및 테스트 화이트 리스트 설정:위 챗 공식 플랫폼 C 위 챗 결제 C 개발 설정,테스트 권한 수여 디 렉 터 리 는 마지막 단계 까지 구체 적 으로 설정 합 니 다.
3.사용자 openid 를 가 져 옵 니 다.OpenID 는 공중 번호 1 대 1 로 해당 하 는 사용자 신분 의 표지 입 니 다.
① 위 챗 홈 페이지 는 사용자 정보 문 서 를 얻 을 수 있 는 권한 을 부여 한다.https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/functions/userinfo.html.문서 패키지 url 에 따라 사용자 가 위 챗 에서 이 링크 를 클릭 하여 openid 등 기본 정 보 를 얻 도록 유도 합 니 다.
② 사용자 가 url 을 클릭 하도록 유도 합 니 다(예 를 들 어 공중 번호 로 이 링크 를 푸 시 합 니 다).형식 은 다음 과 같 습 니 다.
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
각 매개 변 수 는 교체 해 야 합 니 다.의 미 는 다음 과 같 습 니 다.
REDIRECT_URI:URL 을 바 꾸 면 상품 목록 페이지 나 상품 페이지 로 이동 할 수 있 습 니 다.사용자 권한 이 성공 하면 이 URL 이 가리 키 는 페이지 로 이동 합 니 다.
scope:snsapi_base 와 snsapiuserinfo 두 가지,snsapibase 사용자 에 게 침묵 권한 부여,snsapiuserinfo 는 사용자 가 인증 확인 을 해 야 더 많은 사용자 정 보 를 얻 을 수 있 습 니 다.본문 은 후 자 를 선택한다.
state:방향 을 바 꾼 후 이 인 자 를 가 져 옵 니 다.
③ 사용자 가 권한 을 수 여 받 은 후에 방향 을 바 꾸 는 페이지 는 code 인 자 를 얻 습 니 다(사용자 가 권한 을 수 여 받 지 못 하면 방향 을 바 꾼 후에 code 인 자 를 가 져 오지 않 고 state 파라미터 redirect 만 가 져 옵 니 다.uri?state=STATE),공식 적 으로 code 매개 변수 에 대한 설명 은 다음 과 같다.
code 교환 accesstoken 의 어음 은 사용자 권한 수여 에 따 른 code 가 다 릅 니 다.code 는 한 번 만 사용 할 수 있 고 5 분 동안 자동 으로 만 료 되 지 않 습 니 다.
페이지 에 대응 하 는 controller 에서 String code = getPara("code"); 을 통 해 code 인 자 를 가 져 옵 니 다.
④ contoller 에서 WxPayUtil 의 방법 을 동시에 이용 하여 위 챗 인 터 페 이 스 를 호출 하여 현재 사용자 openid 를 가 져 오고 이 openid 를 session 에 저장 합 니 다.

setSessionAttr("openid", (WxPayUtil.getOpenIdByCode(code)).get("openid"));
4,사용자 선택 상품 클릭 지불,업 체 제공 h5 페이지 확인 지불 대응 controller 에서 통일 주문 을 획득 prepayid(여기 서 주의 하 셔 야 합 니 다.주문 금액 은 단위 로 전환 합 니 다).아래 의 공식 문서 주 소 를 통일 하 는 것 은 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1 이다.

//    ,  xml, return_code        ,  prepay_id        
String prePayInfoXml = WxPayUtil.unifiedOrder("WxPay", userOrder.getStr("orderNo"), (entity.getBigDecimal("orderMoney").multiply(new BigDecimal(100))).intValue(), WxPayUtil.getIpAddr(getRequest()), getSessionAttr("openid").toString());
//    prepay_id map,map    
map = WxPayUtil.getPayMap(prePayInfoXml);
//      map,       
map.put("orderNo",userOrder.getStr("orderNo"));
5.전단 에서 이전 맵 을 획득 한 후 위 챗 으로 JSPI 를 지불 합 니 다.전단 js 코드 는 다음 과 같 습 니 다.

<script type="text/javascript">
function payPublic(){
  Common.AjaxSubmitBind("saveForm",function(){
    saveIndex=Common.Loading("     ");
  },function(data){
    prepay_id = data.prepay_id;
    paySign = data.paySign;
    appId = data.appId;
    timeStamp = data.timeStamp;
    nonceStr = data.nonceStr;
    packageStr = data.packageStr;
    signType = data.signType;
    orderNo = data.orderNo;
    callpay();
  },function(errMsg,errCode){
    Common.Alert(errMsg);
  });
}
var prepay_id;
var paySign;
var appId;
var timeStamp;
var nonceStr;
var packageStr;
var signType;
var orderNo;

function onBridgeReady(){
  WeixinJSBridge.invoke(
    'getBrandWCPayRequest', {
      "appId"   : appId,   //     ,     
      "timeStamp" : timeStamp, //   , 1970      
      "nonceStr" : nonceStr , //   
      "package"  : packageStr,
      "signType" : signType, //      :
      "paySign"  : paySign  //    
    },
    function(res){
      if(res.err_msg == "get_brand_wcpay_request:ok" ) {
        alert("    ");
        window.location.href="${base}/test/paySuccess" rel="external nofollow" ;
      }
      if (res.err_msg == "get_brand_wcpay_request:cancel") { 
        alert("    "); 
        window.location.href="${base}/test/cancel" rel="external nofollow" ;
      } 
      if (res.err_msg == "get_brand_wcpay_request:fail") { 
        alert("    "); 
        window.location.href="${base}/test/fail" rel="external nofollow" ;
      } 
    }
  );
}
function callpay(){
  if (typeof WeixinJSBridge == "undefined"){
    if( document.addEventListener ){
      document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
    }else if (document.attachEvent){
      document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
      document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
    }
  }else{
    onBridgeReady();
  }
}
</script>
6.사용자 가 결 제 를 완성 하고 백 스테이지 에서 위 챗 결제 의 리 턴 을 기다 리 며 결제 성공 후 작업 을 합 니 다.
① 사용자 가 비밀 번 호 를 입력 하여 결제 완료.백 엔 드 리 셋 주소(아래 목록 에 설 정 된 notify 통일url)위 챗 결제 결 과 를 받 아 결제 결 과 를 판단 하고 이에 대응 하 는 작업 을 한다.

public void notify(){
  System.out.print("            "); 
  HttpServletRequest request = getRequest();
  String resXml = WxPayUtil.getNotifyResult(request);
  //         ,    (SUCCESS),          ,         8 
  renderText(resXml, "text/xml");
}
관련 도구 및 상수 류 는 다음 과 같 습 니 다.
① WxPayUtil 류(결제 도구 류):

public class WxPayUtil {
  private static Logger logger = Logger.getLogger(WxPayUtil.class); 
  /**
   *   code  openid
   * @param code
   * @return
   * @throws IOException
   */
   public static Map<String,Object> getOpenIdByCode(String code) throws IOException {
    //       access_token
    HttpPost httppost = new HttpPost("https://api.weixin.qq.com/sns/oauth2/access_token");
    //      
    String reqEntityStr = "appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
    reqEntityStr = reqEntityStr.replace("APPID", WxPayConstants.APPID);
    reqEntityStr = reqEntityStr.replace("SECRET", WxPayConstants.APP_SECRET);
    reqEntityStr = reqEntityStr.replace("CODE", code);
    StringEntity reqEntity = new StringEntity(reqEntityStr);
    //    
    httppost.setEntity(reqEntity);
    //     
    CloseableHttpClient httpclient = HttpClients.createDefault();
    //    
    CloseableHttpResponse response = httpclient.execute(httppost);
    //      
    String strResult = EntityUtils.toString(response.getEntity(), Charset.forName("utf-8"));
    //  openid
    JSONObject jsonObject = new JSONObject(strResult);
    Map<String,Object> map = new HashMap<String,Object>();
    map.put("openid",jsonObject.get("openid"));
    map.put("access_token",jsonObject.get("access_token"));
    map.put("refresh_token",jsonObject.get("refresh_token"));
    return map;
  }
  /**
   *     
   * @param body
   * @param out_trade_no
   * @param total_fee
   * @param IP
   * @param notify_url
   * @param openid
   * @return
   * @throws IOException
   */
  public static String unifiedOrder(String body,String out_trade_no,Integer total_fee,String IP,String openid)throws IOException {
    //      
    HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder");

    String nonce_str = getNonceStr().toUpperCase();//  
    //      ,  ASCII  
    String sign = "appid=" + WxPayConstants.APPID +
            "&body=" + body +
            "&mch_id=" + WxPayConstants.MCH_ID +
            "&nonce_str=" + nonce_str +
            "&notify_url=" + WxPayConstants.NOTIFY_URL +
            "&openid=" + openid +
            "&out_trade_no=" + out_trade_no +
            "&spbill_create_ip=" + IP +
            "&total_fee=" + total_fee.toString() +
            "&trade_type=" + WxPayConstants.TRADE_TYPE_JS + 
            "&key=" + WxPayConstants.KEY;//         MD5   ,     ascii     
    sign = ToolMD5.MD5Encode(sign,"").toUpperCase();

    //    openid             XML
    StringBuilder sb = new StringBuilder("");
    sb.append("<xml>");
    setXmlKV(sb,"appid",WxPayConstants.APPID);
    setXmlKV(sb,"body",body);
    setXmlKV(sb,"mch_id",WxPayConstants.MCH_ID);
    setXmlKV(sb,"nonce_str",nonce_str);
    setXmlKV(sb,"notify_url",WxPayConstants.NOTIFY_URL);
    setXmlKV(sb,"openid",openid);
    setXmlKV(sb,"out_trade_no",out_trade_no);
    setXmlKV(sb,"spbill_create_ip",IP);
    setXmlKV(sb,"total_fee",total_fee.toString());
    setXmlKV(sb,"trade_type",WxPayConstants.TRADE_TYPE_JS);
    setXmlKV(sb,"sign",sign);
    sb.append("</xml>");
    System.out.println("      :" + sb);

    StringEntity reqEntity = new StringEntity(new String (sb.toString().getBytes("UTF-8"),"ISO8859-1"));//                     
    httppost.setEntity(reqEntity);
    CloseableHttpClient httpclient = HttpClients.createDefault();
    CloseableHttpResponse response = httpclient.execute(httppost);
    String strResult = EntityUtils.toString(response.getEntity(), Charset.forName("utf-8"));
    System.out.println("      xml:" + strResult);

    return strResult;
  }
  /**
   *               id             map(      )
   * @param prePayInfoXml
   * @return
   */
  public static Map<String,Object> getPayMap(String prePayInfoXml){
    Map<String,Object> map = new HashMap<String,Object>();

    String prepay_id = getXmlPara(prePayInfoXml,"prepay_id");//      xml prepay_id
    String timeStamp = String.valueOf((System.currentTimeMillis()/1000));//1970       
    String nonceStr = getNonceStr().toUpperCase();//       
    String packageStr = "prepay_id=" + prepay_id;
    String signType = "MD5";
    String paySign =
        "appId=" + WxPayConstants.APPID +
        "&nonceStr=" + nonceStr +
        "&package=prepay_id=" + prepay_id +
        "&signType=" + signType +
        "&timeStamp=" + timeStamp +
        "&key="+ WxPayConstants.KEY;//          ASCII    
    paySign = ToolMD5.MD5Encode(paySign,"").toUpperCase();//   MD5  

    map.put("appId",WxPayConstants.APPID);
    map.put("timeStamp",timeStamp);
    map.put("nonceStr",nonceStr);
    map.put("packageStr",packageStr);
    map.put("signType",signType);
    map.put("paySign",paySign);
    map.put("prepay_id",prepay_id);
    return map;
  }
  /**
   *       ,        
   * @param request
   * @return
   */
  public static String getNotifyResult(HttpServletRequest request){
    String inputLine; 
    String notifyXml = "";
    String resXml = "";
    try { 
      while ((inputLine = request.getReader().readLine()) != null){ 
        notifyXml += inputLine; 
      } 
      request.getReader().close(); 
    } catch (Exception e) { 
      logger.debug("xml    :" + e);
      e.printStackTrace();
    }
    System.out.println("    xml:" + notifyXml);
    logger.debug("        :"); 
    logger.debug(notifyXml); 
    if(ToolString.isEmpty(notifyXml)){ 
      logger.debug("xml  :"); 
    }

    String appid = getXmlPara(notifyXml,"appid");; 
    String bank_type = getXmlPara(notifyXml,"bank_type"); 
    String cash_fee = getXmlPara(notifyXml,"cash_fee");
    String fee_type = getXmlPara(notifyXml,"fee_type"); 
    String is_subscribe = getXmlPara(notifyXml,"is_subscribe"); 
    String mch_id = getXmlPara(notifyXml,"mch_id"); 
    String nonce_str = getXmlPara(notifyXml,"nonce_str"); 
    String openid = getXmlPara(notifyXml,"openid"); 
    String out_trade_no = getXmlPara(notifyXml,"out_trade_no");
    String result_code = getXmlPara(notifyXml,"result_code");
    String return_code = getXmlPara(notifyXml,"return_code");
    String sign = getXmlPara(notifyXml,"sign");
    String time_end = getXmlPara(notifyXml,"time_end");
    String total_fee = getXmlPara(notifyXml,"total_fee");
    String trade_type = getXmlPara(notifyXml,"trade_type");
    String transaction_id = getXmlPara(notifyXml,"transaction_id");

    //    xml      
    String localSign =
        "appid=" + appid +
        "&bank_type=" + bank_type +
        "&cash_fee=" + cash_fee +
        "&fee_type=" + fee_type +
        "&is_subscribe=" + is_subscribe +
        "&mch_id=" + mch_id +
        "&nonce_str=" + nonce_str +
        "&openid=" + openid +
        "&out_trade_no=" + out_trade_no +
        "&result_code=" + result_code +
        "&return_code=" + return_code +
        "&time_end=" + time_end +
        "&total_fee=" + total_fee +
        "&trade_type=" + trade_type +
        "&transaction_id=" + transaction_id +
        "&key=" + WxPayConstants.KEY;//          ASCII    
    localSign = ToolMD5.MD5Encode(localSign,"").toUpperCase();//   MD5  

    System.out.println("     :" + localSign);
    logger.debug("     :" + localSign); 
    logger.debug("       :" + sign);

    //               ||        
    if(!sign.equals(localSign) || !"SUCCESS".equals(result_code) || !"SUCCESS".equals(return_code)){
      System.out.println("              "); 
      logger.error("              ");
      resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[FAIL]]></return_msg>" + "</xml> ";
    }else{
       System.out.println("    ");
       logger.debug("       ,out_trade_no(   ) :" + out_trade_no);
       resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
    }
    return resXml;
  }
  /**
   *   32      
   * @return
   */
  public static String getNonceStr(){
    String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    StringBuilder sb = new StringBuilder();
    Random rd = new Random();
    for(int i = 0 ; i < 32 ; i ++ ){
      sb.append(str.charAt(rd.nextInt(str.length())));
    }
    return sb.toString();
  }
  /**
   *   XML  
   * @param sb
   * @param Key
   * @param value
   * @return
   */
  public static StringBuilder setXmlKV(StringBuilder sb,String Key,String value){
    sb.append("<");
    sb.append(Key);
    sb.append(">");

    sb.append(value);

    sb.append("</");
    sb.append(Key);
    sb.append(">");

    return sb;
  }

  /**
   *   XML      para    
   * @param xml
   * @param para
   * @return
   */
  public static String getXmlPara(String xml,String para){
    int start = xml.indexOf("<"+para+">");
    int end = xml.indexOf("</"+para+">");

    if(start < 0 && end < 0){
      return null;
    }
    return xml.substring(start + ("<"+para+">").length(),end).replace("<![CDATA[","").replace("]]>","");
  }

  /**
   *   ip  
   * @param request
   * @return
   */
  public static String getIpAddr(HttpServletRequest request) { 
    InetAddress addr = null; 
    try { 
      addr = InetAddress.getLocalHost(); 
    } catch (UnknownHostException e) { 
      return request.getRemoteAddr(); 
    } 
    byte[] ipAddr = addr.getAddress(); 
    String ipAddrStr = ""; 
    for (int i = 0; i < ipAddr.length; i++) { 
      if (i > 0) { 
        ipAddrStr += "."; 
      } 
      ipAddrStr += ipAddr[i] & 0xFF; 
    } 
    return ipAddrStr; 
  }
}
② 상수 류(사업 자 정보 에 따라 설정):

public class WxPayConstants {
  //       ID
  public static String APPID = "";
  //           
  public static String APP_SECRET = "";
  //  ID
  public static String MCH_ID = "";
  //      -    -    -api  ,  32 key
  public static String KEY = "";
  //    
  public static String TRADE_TYPE_JS = "JSAPI";
  //      url
  public static String NOTIFY_URL = "";
}
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기