微信app支付开发_微信开发之服务器微信支付接口笔记-(与app端对接) - CSDN
精华内容
参与话题
  • 最新微信app支付开发填坑篇

    千次阅读 2019-01-27 10:22:26
    之前开发过高德地图的,百度地图的,人家官网的资料,开发文档,官方论坛,应有尽有,特别详细。微信支付相对支付宝支付,操作繁琐了很多,而且有些文档上的说明太过专业,导致问题多多。 首先他们官网上面只有...

    之前开发过高德地图的,百度地图的,人家官网的资料,开发文档,官方论坛,应有尽有,特别详细。微信支付相对支付宝支付,操作繁琐了很多,而且有些文档上的说明太过专业,导致问题多多。

    首先他们官网上面只有eclipse的案列说明,没有Android studio版本的,其实也没什么太大的区别,注意一点就行了

    在调用微信支付之前,首先要申请微信开放平台帐号,微信商户平台帐号,还有在微信开放平台添加移动应用等等操作都要先做到位,不然是没法支付的

    1、首先你要申请微信开放平台,然后完成后,进入开放平台的管理中心,创建移动应用,应用审核成功后会直接拥有微信分享、收藏等功能,而app支付需要另外再申请

    这里写图片描述

    然后进行微信支付的申请,申请需要填写资料进行审核,而且还需要微信商户帐号,关联商户帐号,获得商户key(商户key在后面生成sign值时需要用到)

    2、服务器那边应该要操作的是,首先调用微信统一下单接口,需要用到多个参数(包括商户key)进行调用接口,成功后会获得应该返回给我们的参数,这一次返回值当中会有sign值,但是该sign值不需要用到,也不需要返回给我们app端,这里需要特别注意的一点是,后台服务需要二次签名,就是把调用统一下单接口返回的值(主要六个参数appid,partnerid,prepayid,package,noncestr,timestamp),进行二次签名得到sign,该sign就是app端需要用到的。(因为进行签名的时候需要用到商户key,商户key比较敏感,所以签名步骤需要放在服务器端进行,签名之后由app端请求返回)

    3、接下来就是介绍app端要操作的步骤,首先,你需要对你的app进行打包操作,获得keystone文件,或者,然后运行微信官网提供的app获取你的应用签名,操作如下
    这里写图片描述
    输入包名,就可以获得你的应用签名(这里需要注意的是,需要打包后的app,而不是直接运行的),然后进入微信开放平台,在你的应用那里添加。由于需要保证支付安全,需要在开放平台绑定商户应用包名和应用签名,设置好后才能正常发起支付。如下图所示

    这里写图片描述

    接下来就是app调用了,在App调用当中,首先要先注册app,就是往微信客户端添加你的应用,还要引入官网提供的jar包,相信引包的操作大家都会了,然后才可以进行app支付
    final IWXAPI msgApi = WXAPIFactory.createWXAPI(context, null);
    // 将该app注册到微信
    msgApi.registerApp(“wxd930ea5d5a258f4f”);

    app支付中,我们客户端请求服务器接口,回调需要的参数,然后根据参数进行app支付请求,,具体操作如下

    这里写图片描述
    上图是微信官网上的案例,上面有个错误的地方,大家自己改过来,还有这里的sign,是服务器那边进行二次签名得到的sign,而不是调用统一下单接口得到的sign,服务器后台的工作人员请特别注意。(本人被这个sign给坑了好几天了)

    然后就是支付回调这一块了,这一块也是超级坑爹的,我从这一块就觉得微信好霸道。
    你需要在你的应用包名相同路径下创建一个包路径wxapi,然后在下面再创建WXPayEntryActivity类,比如说你的应用包名是com.example.app,那么你就需要在com.example.app.wxapi下面创建WXPayEntryActivity类,而且微信那边特别强调,如包名或类名不一致会造成无法回调结果(微信够霸道吧)。。。而且我发现,Android studio上面开发的话,还有一个很坑爹的情况,就是as上的包名可以在build.gradle上面指定为applicationId,然后在AndroidManifest文件上的package另外命名包路径,这时候就有问题了,因为微信指定是AndroidManifest文件上的package的包名,但是你却随便路径,不与应用包名一致,结果导致你连回调结果都不可能实现,参考一下官网资料,如下图所示

    这里写图片描述
    还有配置文件记得给WXPayEntryActivity类加入android:exported=“true”,不然即使回调成功也不会出现该结果界面,也顺便加上启动模式吧android:launchMode=“singleTop”

    <activity
                android:name=".wxapi.WXPayEntryActivity"
                android:exported="true"
                android:launchMode="singleTop"
                android:theme="@android:style/Theme.NoTitleBar" />
    

    当你没其他问题时,你会回调成功,回调成功,并不一定调用支付成功
    回调中errCode值列表:
    名称描述解决方案0成功展示成功页面-1错误可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等。-2用户取消无需处理。发生场景:用户不支付了,点击取消,返回APP。

    回调中errCode值列表

    这个微信支付的流程全部搞定了,结果是一直返回-1给我,试过很多方法都不行,最后才知道sign需要经过二次签名,呵呵,官网api都没说清楚,很多地方都让人不明不白,出的问题特别多,真是有趣的微信支付。

    有关微信支付的就到此为止了,应该没有什么问题,有问题的话可以在下面留言,我会及时回复的

    展开全文
  • http://blog.csdn.net/paymm/article/details/73498182
     微信APP支付又称移动端支付,是商户通过在移动端应用APP中集成开放SDK调起微信支付模块完成支付的模式。
    支付方式 报错提示 解决方法
    热点问题 支付返回签名错误 注意签名参数的大小写,支付密钥key要到商户平台设置,设置的规则是32位数字与字母大小写的组合。以下链接为签名过程。
    (https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=3_1)
    支付回调 认证后的服务号之间支持跨号支付。
    支付失败 请检查商户号是否错误或支付密钥key设置错误。
    redirect——uri参数错误 请进入公众平台-开发者中心,找到填写商户的支付授权域名,填写的就是商户支付授权目录上的域名。
    paysinkey如何获取? 新版的微信支付是没有这个paysignkey参数的,具体的参数请查看文档
    (https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=3_1)
    mchid是指什么? MCHID参数指的是商户号
    openid的获取请参考文档 openid的获取请参考文档详细介绍
    (http://mp.weixin.qq.com/wiki/14/bb5031008f1494a59c6f71fa0f319c66.html)
    openid如何获取? openid的获取请参考文档查看详细介绍:
    (http://mp.weixin.qq.com/wiki/14/bb5031008f1494a59c6f71fa0f319c66.html)
    Appsecret如何获取? APPsecret参数可进入公众平台(https://mp.weixin.qq.com)开发者中心查看。
    调用报错 签名错误,请仔细检查签名。
    get_brand_wcpay_request:fail
    spbill_create_ip 是指什么? spbill_create_ip 指的是终端ip,在APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。
    展开全文
  • 微信APP支付-Java后台实现

    万次阅读 热门讨论 2020-09-23 17:13:42
    因为自己项目上的APP 原来有支付宝支付,现在想要加上微信支付,所以去研究了微信APP支付的相关技术文档。虽然微信的相关的技术文档已经非常的清楚了。但是我还是想记录一下自己研究过程。 1 注册微信开放者平台...
     因为自己项目上的APP 原来有支付宝支付,现在想要加上微信支付,所以去研究了微信APP支付的相关技术文档。虽然微信的相关的技术文档已经非常的清楚了。但是我还是想记录一下自己研究过程。
    

    1 注册微信开放者平台

    开发者平台地址:https://open.weixin.qq.com/
    ####2 成为开发者
    这里写图片描述

    3 上传APP

    这里写图片描述

    4 开通微信支付功能

    这里写图片描述

    5 设置商户号信息

    APP 支付能力开通后,微信会给你一个商户号,用户和密码等信息。需要验证商户信息,还需要设置一个加密的密钥字段,这里就不一一细说了。

    6 开发接口

    微信APP支付接口,是很好调试的,(不像微信公众平台,需要80端口),可以直接在本地就可以进行调试。 具体业务就不细说,直接看代码就懂了。

    1 基础信息配置
    package com.cat.common.pay.weiChat.config;
    
    import java.util.Properties;
    
    import com.cat.common.properties.PropertiesUtil;
    
    
    public class WeiChartConfig {
       
       /**
        * 预支付请求地址
        */
       public static final String  PrepayUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
      
       /**
        * 查询订单地址
        */
       public static final String  OrderUrl = "https://api.mch.weixin.qq.com/pay/orderquery";
      
       /**
        * 关闭订单地址
        */
       public static final String  CloseOrderUrl = "https://api.mch.weixin.qq.com/pay/closeorder";
      
       /**
        * 申请退款地址
        */
       public static final String  RefundUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";
      
       /**
        * 查询退款地址
        */
       public static final String  RefundQueryUrl = "https://api.mch.weixin.qq.com/pay/refundquery";
      
       /**
        * 下载账单地址
        */
       public static final String  DownloadBillUrl = "https://api.mch.weixin.qq.com/pay/downloadbill";
      
       /**
        * 商户APPID
        */
       public static final String  AppId = "wx1234567890";
       
       /**
        * 商户账户
        */
       public static final String  MchId = "1234567890";
       
       /**
        * 商户秘钥
        */
       public static final String  AppSercret = "123456789098765432123";
       
       /**
        * 服务器异步通知页面路径
        */
       public static String notify_url = getProperties().getProperty("notify_url");
       
       /**
        * 页面跳转同步通知页面路径
        */
       public static String return_url = getProperties().getProperty("return_url");
       
       /**
        * 退款通知地址
        */
       public static String refund_notify_url = getProperties().getProperty("refund_notify_url");
       
       /**
        * 退款需要证书文件,证书文件的地址
        */
       public static String refund_file_path = getProperties().getProperty("refund_file_path");
       
       /**
        * 商品名称
        */
       public static String subject =  getProperties().getProperty("subject");
       
       /**
        * 商品描述
        */
       public static String body = getProperties().getProperty("body");
       
       private static  Properties properties;
    
       public static synchronized Properties getProperties(){
          if(properties == null){
    //         String path = System.getenv(RSystemConfig.KEY_WEB_HOME_CONF) + "/weichart.properties";//自定义配置文件路径
             String path = "d://weichart.properties";//测试路径
             properties = PropertiesUtil.getInstance().getProperties(path);
          }
          return properties;
       }
    
    }
    
    

    这里是 PropertiesUtil 类

    package com.cat.common.properties;
    
    import java.io.BufferedInputStream;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Properties;
    
    public class PropertiesUtil{
       
       private static PropertiesUtil instance;
       
       private Properties properties = new Properties();
       
       public synchronized static PropertiesUtil getInstance() {
          if(null == instance) {
             instance = new PropertiesUtil();
          }
          return instance;
       }
       
       /**
        * 获取配置
        * @param fileUrl
        * @return
        */
       public Properties getProperties(String fileUrl){
          readProperties(fileUrl);
          return properties;
       }
    
       /**
        * 读取properties的全部信息
        * @param filePath
        */
       public void readProperties(String filePath){
          InputStream in = null;
          try{
             in = new BufferedInputStream(new FileInputStream(filePath));
             properties.load(in);
          }catch(Exception e){
             e.printStackTrace();
          }finally{
             try{
                if(in != null)
                   in.close();
             }catch(IOException e){
                e.printStackTrace();
             }
          }
       }
    }
    
    
    2 http /https请求的工具类

    其中有需要证书的,也有不需要证书的。
    证书是在需要退款接口的时候需要使用,直接把证书放在服务器上,然后传路径

    package com.qx.client.common.pay.weichart.util.httpClient;
    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLConnection;
    import java.security.KeyStore;
    import java.util.Map;
    
    import javax.net.ssl.SSLContext;
    
    import org.apache.commons.httpclient.HttpClient;
    import org.apache.commons.httpclient.methods.PostMethod;
    import org.apache.commons.httpclient.methods.StringRequestEntity;
    import org.apache.commons.httpclient.params.HttpMethodParams;
    import org.apache.http.HttpEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.SSLContexts;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.util.EntityUtils;
    
    public class HttpClientUtil{
    
       public static String post(String url,
                                 Map<String, String> headMap,
                                 Map<String, String> params){
          try{
             HttpClient httpclient = new HttpClient();
             httpclient.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
             PostMethod httpPost = new PostMethod(url);
             if(null != headMap){
                for(String key : headMap.keySet()){
                   httpPost.setRequestHeader(key, headMap.get(key));
                }
             }
    
             if(null != params){
                for(String pkey : params.keySet()){
                   httpPost.addParameter(pkey, params.get(pkey));
                }
             }
             httpclient.executeMethod(httpPost);
    
             BufferedReader reader = new BufferedReader(new InputStreamReader(httpPost.getResponseBodyAsStream()));
             StringBuffer stringBuffer = new StringBuffer();
             String str = "";
             while((str = reader.readLine()) != null){
                stringBuffer.append(str);
             }
             reader.close();
             return stringBuffer.toString();
          }catch(Exception e){
             e.printStackTrace();
          }
          return null;
       }
    
       public static String postHttplient(String url,
                                          String xmlInfo){
          try{
             HttpClient httpclient = new HttpClient();
             httpclient.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
             PostMethod httpPost = new PostMethod(url);
             httpPost.setRequestEntity(new StringRequestEntity(xmlInfo));
             httpclient.executeMethod(httpPost);
    
             BufferedReader reader = new BufferedReader(new InputStreamReader(httpPost.getResponseBodyAsStream()));
             StringBuffer stringBuffer = new StringBuffer();
             String str = "";
             while((str = reader.readLine()) != null){
                stringBuffer.append(str);
             }
             reader.close();
             return stringBuffer.toString();
          }catch(Exception e){
             e.printStackTrace();
          }
          return null;
       }
    
       /**
        * 需要加密执行的
        * @param url
        * @param xmlInfo
        * @return
        * @throws Exception 
        */
       public static String postHttplientNeedSSL(String url,
                                                 String xmlInfo,
                                                 String cretPath,
                                                 String mrchId)
             throws Exception{
          //选择初始化密钥文件格式
          KeyStore keyStore = KeyStore.getInstance("PKCS12");
          //得到密钥文件流
          FileInputStream instream = new FileInputStream(new File(cretPath));
          try{
             //用商户的ID 来解读文件
             keyStore.load(instream, mrchId.toCharArray());
          }finally{
             instream.close();
          }
          //用商户的ID 来加载
          SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mrchId.toCharArray()).build();
          // Allow TLSv1 protocol only
          SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
          //用最新的httpclient 加载密钥
          CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
          StringBuffer ret = new StringBuffer();
          try{
             HttpPost httpPost = new HttpPost(url);
             httpPost.setEntity(new StringEntity(xmlInfo));
             CloseableHttpResponse response = httpclient.execute(httpPost);
             try{
                HttpEntity entity = response.getEntity();
                if(entity != null){
                   BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
                   String text;
                   while((text = bufferedReader.readLine()) != null){
                      ret.append(text);
                   }
                }
                EntityUtils.consume(entity);
             }finally{
                response.close();
             }
          }finally{
             httpclient.close();
          }
          return ret.toString();
       }
    
       public static String postHtpps(String urlStr,
                                      String xmlInfo){
          try{
             URL url = new URL(urlStr);
             URLConnection con = url.openConnection();
             con.setDoOutput(true);
             con.setRequestProperty("Pragma:", "no-cache");
             con.setRequestProperty("Cache-Control", "no-cache");
             con.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
             OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream(), "utf-8");
             out.write(xmlInfo);
             out.flush();
             out.close();
             BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
             StringBuffer lines = new StringBuffer();
             String line = "";
             for(line = br.readLine(); line != null; line = br.readLine()){
                lines.append(line);
             }
             return lines.toString();
          }catch(MalformedURLException e){
             e.printStackTrace();
          }catch(IOException e){
             e.printStackTrace();
          }
          return null;
       }
    
    }
    
    
    
    4 调用API接口

    其中包含 XML生成,和解析XML,请求参数字典排序,拼接密钥,MD5加密

    这里是核心和微信交互的类。

    package com.cat.common.pay.weiChat;
    
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    import java.util.Arrays;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Random;
    import java.util.Set;
    
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.DocumentHelper;
    import org.dom4j.Element;
    
    import com.cat.common.pay.weiChat.config.WeiChartConfig;
    import com.cat.common.pay.weiChat.util.HttpClientUtil;
    
    public class WeiChartUtil{
    
       /**
        * 返回状态码
        */
       public static final String ReturnCode = "return_code";
       
       /**
        * 返回信息
        */
       public static final String ReturnMsg = "return_msg";
       
       /**
        * 业务结果
        */
       public static final String ResultCode = "result_code";
       
       /**
        * 预支付交易会话标识
        */
       public static final String PrepayId = "prepay_id";
       /**
        * 得到微信预付单的返回ID
        * @param orderId  商户自己的订单号
        * @param totalFee  总金额  (分)
        * @return
        */
       public static Map<String, String> getPreyId(String orderId,
                                      String totalFee,String schoolLabel){
          Map<String, String> reqMap = new HashMap<String, String>();
          reqMap.put("appid", WeiChartConfig.AppId);
          reqMap.put("mch_id", WeiChartConfig.MchId);
          reqMap.put("nonce_str", getRandomString());
     
          reqMap.put("body", "【"+schoolLabel+"】"+ WeiChartConfig.body);
          //reqMap.put("detail", WeiChartConfig.subject); //非必填
          //reqMap.put("attach", "附加数据"); //非必填
          reqMap.put("out_trade_no", orderId); //商户系统内部的订单号,
          reqMap.put("total_fee", totalFee); //订单总金额,单位为分
          reqMap.put("spbill_create_ip", getHostIp()); //用户端实际ip
          // reqMap.put("time_start", "172.16.40.18"); //交易起始时间 非必填
          // reqMap.put("time_expire", "172.16.40.18"); //交易结束时间  非必填
          // reqMap.put("goods_tag", "172.16.40.18"); //商品标记 非必填
          reqMap.put("notify_url", WeiChartConfig.notify_url); //通知地址
          reqMap.put("trade_type", "APP"); //交易类型
          //reqMap.put("limit_pay", "no_credit"); //指定支付方式,no_credit 指定不能使用信用卡支  非必填
          reqMap.put("sign", getSign(reqMap));
    
          String reqStr = creatXml(reqMap);
          String retStr = HttpClientUtil.postHtpps(WeiChartConfig.PrepayUrl, reqStr);
          return getInfoByXml(retStr);
       }
    
       /**
        * 关闭订单
        * @param orderId  商户自己的订单号
        * @return
        */
       public static Map<String, String> closeOrder(String orderId){
          Map<String, String> reqMap = new HashMap<String, String>();
          reqMap.put("appid", WeiChartConfig.AppId);
          reqMap.put("mch_id", WeiChartConfig.MchId);
          reqMap.put("nonce_str", getRandomString());
          reqMap.put("out_trade_no", orderId); //商户系统内部的订单号,
          reqMap.put("sign", getSign(reqMap));
    
          String reqStr = creatXml(reqMap);
          String retStr = HttpClientUtil.postHtpps(WeiChartConfig.CloseOrderUrl, reqStr);
          return getInfoByXml(retStr);
       }
    
       
       /**
        * 查询订单
        * @param orderId 商户自己的订单号
        * @return
        */
       public static String getOrder(String orderId){
          Map<String, String> reqMap = new HashMap<String, String>();
          reqMap.put("appid", WeiChartConfig.AppId);
          reqMap.put("mch_id", WeiChartConfig.MchId);
          reqMap.put("nonce_str", getRandomString());
          reqMap.put("out_trade_no", orderId); //商户系统内部的订单号,
          reqMap.put("sign", getSign(reqMap));
    
          String reqStr = creatXml(reqMap);
          String retStr = HttpClientUtil.postHtpps(WeiChartConfig.OrderUrl, reqStr);
          return retStr;
       }
    
       
       /**
        * 退款
        * @param orderId  商户订单号
        * @param refundId  退款单号
        * @param totralFee 总金额(分)
        * @param refundFee 退款金额(分)
        * @param opUserId 操作员ID
        * @return
        */
       public static Map<String, String> refundWei(String orderId,String refundId,String totralFee,String refundFee,String opUserId){
          Map<String, String> reqMap = new HashMap<String, String>();
          reqMap.put("appid", WeiChartConfig.AppId);
          reqMap.put("mch_id", WeiChartConfig.MchId);
          reqMap.put("nonce_str", getRandomString());
          reqMap.put("out_trade_no", orderId); //商户系统内部的订单号,
          reqMap.put("out_refund_no", refundId); //商户退款单号
          reqMap.put("total_fee", totralFee); //总金额
          reqMap.put("refund_fee", refundFee); //退款金额
          reqMap.put("op_user_id", opUserId); //操作员
          reqMap.put("sign", getSign(reqMap));
    
          String reqStr = creatXml(reqMap);
          String retStr = "";
          try{
             retStr = HttpClientUtil.postHttplientNeedSSL(WeiChartConfig.RefundUrl, reqStr, WeiChartConfig.refund_file_path, WeiChartConfig.MchId);
          }catch(Exception e){
             e.printStackTrace();
             return null;
          }
          return getInfoByXml(retStr);
       }
       
       
       /**
        * 退款查询
        * @param refundId  退款单号
        * @return
        */
       public static Map<String, String> getRefundWeiInfo(String refundId){
          Map<String, String> reqMap = new HashMap<String, String>();
          reqMap.put("appid", WeiChartConfig.AppId);
          reqMap.put("mch_id", WeiChartConfig.MchId);
          reqMap.put("nonce_str", getRandomString());
          reqMap.put("out_refund_no", refundId); //商户退款单号
          reqMap.put("sign", getSign(reqMap));
    
          String reqStr = creatXml(reqMap);
          String retStr = HttpClientUtil.postHtpps(WeiChartConfig.RefundQueryUrl, reqStr);
          return getInfoByXml(retStr);
       }
       
       /**这个方法 可以自己写,以前我使用的是我公司封装的类,后来很多人找我要JAR包,所以我改成了这样,方便部分人直接使用代码,我自己未测试,不过应该问题不大,欢迎使用有问题的找我。
        * 传入map  生成头为XML的xml字符串,例:<xml><key>123</key></xml>
        * @param reqMap
        * @return
        */
       public static String creatXml(Map<String, String> reqMap){
          Set<String> set = reqMap.keySet();
          StringBuffer b = new StringBuffer();
          b.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
          b.append("<xml>");
          for(String key : set){
             b.append("<"+key+">").append(reqMap.get(key)).append("</"+key+">");
          }
          b.append("</xml>");
          return b.toString();
       }
       
       /**
        * 得到加密值
        * @param map
        * @return
        */
       public static String getSign(Map<String, String> map){
          String[] keys = map.keySet().toArray(new String[0]);
          Arrays.sort(keys);
          StringBuffer reqStr = new StringBuffer();
          for(String key : keys){
             String v = map.get(key);
             if(v != null && !v.equals("")){
                reqStr.append(key).append("=").append(v).append("&");
             }
          }
          reqStr.append("key").append("=").append(WeiChartConfig.AppSercret);
        
          return WeiMd5.encode(reqStr.toString()).toUpperCase();
       }
    
       /**
        * 得到10 位的时间戳
        * 如果在JAVA上转换为时间要在后面补上三个0 
        * @return
        */
       public static String getTenTimes(){
          String t = new Date().getTime()+"";
          t = t.substring(0, t.length()-3);
          return t;
       }
       
       /**
        * 得到随机字符串
        * @param length
        * @return
        */
       public static String getRandomString(){
          int length = 32;
          String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
          Random random = new Random();
          StringBuffer sb = new StringBuffer();
    
          for(int i = 0; i < length; ++i){
             int number = random.nextInt(62);//[0,62)  
             sb.append(str.charAt(number));
          }
          return sb.toString();
       }
    
       /**
        * 得到本地机器的IP
        * @return
        */
       private static String getHostIp(){
          String ip = "";
          try{
             ip = InetAddress.getLocalHost().getHostAddress();
          }catch(UnknownHostException e){
             e.printStackTrace();
          }
          return ip;
       }
    
       public static Map<String, String> getInfoByXml(String xmlStr){
          try{
             Map<String, String> m = new HashMap<String, String>();
             Document d = DocumentHelper.parseText(xmlStr);
             Element root = d.getRootElement();
             for ( Iterator<?> i = root.elementIterator(); i.hasNext(); ) {
                Element element = (Element) i.next();
                String name = element.getName();
                if(!element.isTextOnly()){
                   //不是字符串 跳过。确定了微信放回的xml只有根目录
                   continue;
                }else{
                   m.put(name, element.getTextTrim());
                }
             }
             //对返回结果做校验.去除sign 字段再去加密
             String retSign = m.get("sign");
             m.remove("sign");
             String rightSing = getSign(m);
             if(rightSing.equals(retSign)){
                return m;
             }
          }catch(DocumentException e){
             // TODO Auto-generated catch block
             e.printStackTrace();
          }
          return null;
    }
       
       /**
        * 将金额转换成分
        * @param fee 元格式的
        * @return 分
        */
       public static String changeToFen(Double fee){
          String priceStr = "";
          if(fee != null){
              int p = (int)(fee * 100); //价格变为分
              priceStr = Integer.toString(p);
          }
          return priceStr;
       }
       
    }
    
    
    

    这个是这里面使用的MD5加密方法

    package com.cat.common.pay.weiChat;
    
    import java.io.UnsupportedEncodingException;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    /*
     * MD5 算法
    */
    public class WeiMd5 {
        
        // 全局数组
        private final static String[] strDigits = { "0", "1", "2", "3", "4", "5",
                "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
    
        // 返回形式为数字跟字符串
        private static String byteToArrayString(byte bByte) {
            int iRet = bByte;
            // System.out.println("iRet="+iRet);
            if (iRet < 0) {
                iRet += 256;
            }
            int iD1 = iRet / 16;
            int iD2 = iRet % 16;
            return strDigits[iD1] + strDigits[iD2];
        }
    
    
        // 转换字节数组为16进制字串
        private static String byteToString(byte[] bByte) {
            StringBuffer sBuffer = new StringBuffer();
            for (int i = 0; i < bByte.length; i++) {
                sBuffer.append(byteToArrayString(bByte[i]));
            }
            return sBuffer.toString();
        }
    
        public static String encode(String strObj) {
            String resultString = null;
            try {
                resultString = new String(strObj);
                MessageDigest md = MessageDigest.getInstance("MD5");
                // md.digest() 该函数返回值为存放哈希值结果的byte数组
                try{
                   resultString = byteToString(md.digest(strObj.getBytes("UTF-8")));
                }catch(UnsupportedEncodingException e){
                   // TODO Auto-generated catch block
                   e.printStackTrace();
                }
            } catch (NoSuchAlgorithmException ex) {
                ex.printStackTrace();
            }
            return resultString;
        }
    
    }
    

    在微信支付的调试过程中,发现了一个困扰了很长时间的BUG,或者说是一个问题。
    就是微信请求预支付的时候如果传了中文,就是body中给的是中文,就会报body不是UTF-8格式。如果强行对字段进行编码,又会报 加密错误。

    但是这不是最主要的让人困扰的地方,最让我烦恼的是,我用本地的JDK调试的时候,它是OK 的。 但是用TOMCAT 部署的时候 却一直都不行

    在网上有很多的说法,有的说,对body 进行编码转换UTF-8,有的说对整个请求的XML,进行编码。

    还有的说编码格式用统一的。iso900…等等,巴拉巴拉的。。
    反正我都不行。

    最后在大神的帮助下,慢慢梳理,对发送请求的post方法上面想办法。
    然后就是下面的 这句关键

    public static String postHtpps(String urlStr,
                                      String xmlInfo){
          try{
             URL url = new URL(urlStr);
             URLConnection con = url.openConnection();
             con.setDoOutput(true);
             con.setRequestProperty("Pragma:", "no-cache");
             con.setRequestProperty("Cache-Control", "no-cache");
             con.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
             //在输入流里面进行转码,是最重要的
             OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream(), "utf-8");
             out.write(xmlInfo);
             out.flush();
             out.close();
             BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
             StringBuffer lines = new StringBuffer();
             String line = "";
             for(line = br.readLine(); line != null; line = br.readLine()){
                lines.append(line);
             }
             return lines.toString();
          }catch(MalformedURLException e){
             e.printStackTrace();
          }catch(IOException e){
             e.printStackTrace();
          }
          return null;
       }
    
    }
    

    小结:很多人看了我的这篇文章后,就直接COPY了我的代码去使用,然后在我之前发的版本中,有几个生成XML 和 解析XML的 类是我自己封装的JAR包,没有放上来,就很多人找我,加我的QQ留言说 要我给源码。其实那是很简单的一些东西。没必要那么复杂。
    我的建议是 我的是一个启发的DEMO。让你能够尽快的上手使用,但是你自己一定需要好好的去看官方的文档,弄懂所有的流程,才能真正的掌握这个技巧。

    展开全文
  • 微信支付开发APP支付介绍及业务流程 开发中,遇到微信支付需求时,如果是web开发, 那么用H5支付方式即可, 对于开发app, 微信支付开发文档表示, 使用app支付最合适,不然会出现什么情况呢? 想像一下, 当我们点开app的...

    微信支付开发之APP支付介绍及业务流程

    开发中,遇到微信支付需求时,如果是web开发, 那么用H5支付方式即可, 对于开发app, 微信支付开发文档表示, 使用app支付最合适,不然会出现什么情况呢? 想像一下, 当我们点开app的支付功能时, 手机就会打开默认浏览器…

    场景介绍

    H5支付

    H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前述页面确认使用微信支付时,商户发起本服务呼起微信客户端进行支付。
    主要用于触屏版的手机浏览器请求微信支付的场景。
    可以方便的从外部浏览器唤起微信支付。

    **提醒:H5支付不建议在APP端使用,如需要在APP中使用微信支付,请接APP支付,**文档详见微信支付开发文档

    app支付

    app支付适用于商户在移动端APP中集成微信支付功能。
    商户APP调用微信提供的SDK调用微信支付模块,商户APP会跳转到微信中完成支付,支付完后跳回到商户APP内,最后展示支付结果。

    目前微信支付支持手机系统有:IOS(苹果)、Android(安卓)和WP(Windows Phone)。

    app支付交互细节

    步骤1:用户进入商户APP,选择商品下单、确认购买,进入支付环节。商户服务后台生成支付订单,签名后将数据传输到APP端。以微信提供的DEMO为例,见图8.1。

    步骤2:用户点击后发起支付操作,进入到微信界面,调起微信支付,出现确认支付界面,见图8.2。

    步骤3:用户确认收款方和金额,点击立即支付后出现输入密码界面,可选择零钱或银行卡支付见图8.3。

    商户APP界面实例图8.1 商户APP界面实例 跳转到微信支付图8.2 跳转到微信支付 用户确认支付图8.3 用户确认支付

    第四步:输入正确密码后,支付完成,用户端微信出现支付详情页面。见图8.4。

    第五步:回跳到商户APP中,商户APP根据支付结果个性化展示订单处理结果。见图8.5。

    支付成功提示页面图8.4 支付成功提示页面 返回到商户APP提示图8.5 返回到商户APP提示

    业务流程

                              |
    

    业务流程

    APP支付时序图

    展开全文
  • 微信APP支付服务端和Android 端详解及其demo

    万次阅读 多人点赞 2019-08-05 17:28:18
    最近在开发APP微信支付和支付宝支付,Android 端和后端都是我自己开发的,发现两家公司的文档都不是很友好,特别是微信,接触过或者开发过的人都应该有所体会。因此我特意把开发的过程梳理了,做下记录,方便以后...
  • 微信支付app支付3.0接口开发

    千次阅读 2015-10-30 10:12:31
    整个微信支付,分为三大平台,公众平台(就是公众账号那个),开发平台(主要针对app这块),商户平台(所有微信支付的结算,最终在这里).三个平台的账号都不同,而且必须不同,不然不让你注册. 其中,需要用户注册的是公众平台...
  • 最近在开发微信APP支付,包括Android和服务端,我把开发过程做了详细的记录,现在分享出来,包括服务端和安卓端的demo及详细开发文档。
  • 微信APP支付申请配置过程详解

    千次阅读 2018-06-07 11:04:50
    填写应用信息第二步第三步:创建应用之后等待审核第三步第四步:详情中如果微信或获得支付能力,进行申请开通第四步第五步:申请支付能力第五步第六步:登陆商户平台进行最后的配置第六步最后,进行开发即可。...
  • 记一次微信APP支付开发返回-1的坑

    千次阅读 2018-09-21 10:38:58
    微信APP文档 问题出现在5-6-7环节,当我第一次签名后生成预付单的时候返回很正常,表明我的签名没问题,微信商户数据也没问题,但是接收到预付单号把预付单号结合官方文档再次进行签名的时候却频频-1,官方要的...
  • 1-1) 查看微信支付 appid 的方法 微信支付使用的 appid, 是微信服务号的 appid, ...微信支付使用的 appsecret, 是微信服务号的 appsecret, 登录你的微信服务号后台, 在 开发-基本配置/开发者密码(App...
  • 手机浏览器唤起微信app支付说明

    万次阅读 多人点赞 2016-07-08 09:58:59
    微信支付官方文档并没有显示h5唤起微信app支付的文档,但是自微信6.0.2版本后已支持该功能,而且官方已经有了开发文档,只是没有显示出来。 微信h5支付文档地址: ...
  • 微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等...
  • 在iOS APP发起H5微信支付

    万次阅读 2018-01-11 14:43:46
    场景介绍 H5支付是指商户在微信客户端外的移动端网页展示...提醒:H5支付不建议在APP端使用,如需要在APP中使用微信支付,请接APP支付。 这个场景介绍来自微信H5支付的开发文档,说建议不要在APP端使用H5支付,但是
  • 微信支付要细心,仔细才不会走弯路 1、要是按照他上面的驼峰原则来进行签名,那你就大错特错了。 记住:这几个字段的“字段名”在参与签名的时候一定都要改成小写!!! 2、还有个坑要注意:不仔细根本...
  • 在iOS的webview中,h5自己调用微信支付,能够成功起调,并且能完成支付,但是点击完成时,跳转到safari浏览器中,并不能跳回app
  • 如果微信用户没有实名认证,微信零钱支付单笔限额1000元,每日限额1000元,每月限额2000元; 如果已经完成了实名认证,每日限额10000元。每年累计限额是20W。 手机银行限额 ...
  • uniapp app 端调微信支付接口

    万次阅读 2019-05-31 18:57:17
    uni-app 官方文档支付接口如下: uni.requestPayment({ provider: provider, // wxpay、alipay orderInfo: 'orderInfo', //微信、支付宝订单数据 success: function (res) { console.log('success:' + JSON....
  • 微信支付 app支付开发 服务端的那些坑 服务端调用统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。 注:我的服务端使用php写的 第一次签名字段名: appid,body,mch_id,nonce_...
  • 微信支付分为APP支付和公众号支付两大类,其中公众号支付又分为(公众号支付、扫码支付、刷卡支付)。申请两种支付方式分别需要用到两种平台:公众号支付需要(公众平台+商户平台),APP支付需要(开放平台+商户平台)
  • 进入开发 ---》 基本配置 , 获取 AppID以及AppSecret  (2) 配置网页授权域名以及JS接口安全域名 开发 ---》接口权限 ---》网页服务 ---》网页授权 ---》网页授权获取用户基本信息 ---》修改,如下图 点击...
1 2 3 4 5 ... 20
收藏数 31,908
精华内容 12,763
关键字:

微信app支付开发