您的位置:首页 > 移动开发 > 微信开发

微信支付Java后台和Android的接入

2017-05-17 15:40 369 查看
1 微信支付业务流程
https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_3
         商户系统和微信支付系统主要交互说明:

         步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。(在商户后台生成订             单)。

         步骤2:商户后台根据1生成的订单,调用微信支付统一下单接口。(统一下单接口返    回正常的prepay_id,注:这里要处理数据签名)。
         步骤3:商户后台根据 prepay_id,再按签名规范重新生成签名后,将数据(这个数据    是APP支付要的数据,注:这里要处理数据签名)传输给APP。

         步骤4:商户APP调起微信支付。(把3的数据传给微信,用户输入密码,支付成功)。

         步骤5:商户后台接收支付通知。(后台收到微信的异步回调,商户后台处理业务逻辑)。

         完成(前台做的东西不多的,调用统一下单接口,生成APP要的支付参数都放后台)



2 统一下单接口 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1          直接上代码:(我添加的参数都是微信必须的,不是必须的自己定的)
         我写在Servlet里的doGet里面了
      String url ="https://api.mch.weixin.qq.com/pay/unifiedorder";
SortedMap<String,    String> map =new TreeMap<String, String>();
//appid在你创建APP的时候有的,是在微信的开放平台能看到
//https://open.weixin.qq.com/   管理中心
map.put("appid", "wx3333");
//在微信支付商户平台看到
//https://pay.weixin.qq.com/  账户中心--个人中心--登录账号(登录账号就是你的     mch_id)
map.put("mch_id", "136692222");
//随机生成
map.put("nonce_str", String.valueOf(System.currentTimeMillis()));
//自已定义
map.put("body","lidongliang");
//是你商户后台生成的订单号(我这是随便生成的,这个要改为你后台生成的订单号)
map.put("out_trade_no",String.valueOf(System.currentTimeMillis()));
//钱
map.put("total_fee","1");
//IP随便写了一个
map.put("spbill_create_ip","123.12.12.123");
//微信支付成功后的回调接口(就是支付成功后,微信调你商户后台的接口,你在后台 //改订单的状态,例如,改为“成功”)
map.put("notify_url","http://www.weixin.qq.com/wxpay/pay.php");
//APP支付,这是固定的
map.put("trade_type","APP");
//生成签名(重要,把上面的map传到方法里面,返回一个sign信息,诸多人都是在     这里坑了,方法在下面)
String sign = createSign(map);
map.put("sign",sign );

//因为微信要的是XML的形式,所以拼成XML参数形式,如下:
// 生成XMl
Set set = map.entrySet();
Iterator it = set.iterator();
tringBuffer sb = new StringBuffer();
sb.append("<xml>");
while (it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String key = (String)entry.getKey();
String value = (String)entry.getValue();
sb.append("<" +key + "><![CDATA[");
sb.append(value);
sb.append("]]></"+ key + ">");
}
sb.append("</xml>");
//这里不说了,调用接口
String postData = NetUtil.doPost(url,sb.toString());


         //返回正确的结果如下:
       
  <xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wx3333]]></appid>
<mch_id><![CDATA[136692222]]></mch_id>
<nonce_str><![CDATA[vN2FK21GSccXRU6j]]></nonce_str>
<sign><![CDATA[6AF542F0086A0094D904549736564072]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
//很显然这个是prepay_id,是APP端调用微信支付要的参数
<prepay_id><![CDATA[wx20170517120117dda20d35ab0540951436]]></prepay_id>
<trade_type><![CDATA[APP]]></trade_type>
</xml>


         先把XML转成JSON,用到了一个工具,不过用其它的方法也行的,到时候我会上传一  个demo的。
         JSONObject json =XML.toJSONObject(postData).getJSONObject("xml");

2 生成APP端调起支付的参数
 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12&index=2
         接上面的代码
    SortedMap<String, String> test =new TreeMap<String, String>();
// appid是APP端要的参数,是从上面返回的XML中取得
test.put("appid",json.getString("appid"));
// partnerid显然是商户的mch_id也从上面返回的XML中取得
test.put("partnerid",json.getString("mch_id"));
// prepayid微信返回的支付交易会话id, 也从上面返回的XML中取得
test.put("prepayid",json.getString("prepay_id"));
//暂填写固定值Sign=WXPay(微信要求固定就固定的)
test.put("package","Sign=WXPay");
//随机字符串
test.put("noncestr", String.valueOf(System.currentTimeMillis()));
//时间戳
test.put("timestamp",String.valueOf(System.currentTimeMillis() / 1000));
//这个没有什么说的,和原来的一样调用createSign方法
test.put("sign",createSign(test));
//以json的形式返回客户端
response.getWriter().append(new JSONObject(test).toString());
android或ios得到如下结果:
{
timestamp: "1494993676",
sign: "38FB898BC67368BB489F78A07BAC7633",
partnerid: "136692222",
noncestr: "1494993676646",
prepayid: "wx20170517120117dda20d35ab0540951436",
package: "Sign=WXPay",
appid: " wx3333"
}


----------------服务器端完----------------------
3 下面要做的是Android的处理:
下载微信提供的demo  SDK与DEMO下载找到android  下载的是这个“【微信支付】APP 支付示例”
         https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=11_1          当你导入到eclipse的时候,wo kao 那么多的报错(把报错的导入全部删除,重新导入  看一下有什么区别)
         //demo里面的
         importcom.tencent.mm.sdk.constants.ConstantsAPI;
         //更改后的,原来是包名都不一样啊。。。。。。鄙视微信,连一个demo都做的这么的。。。
         importcom.tencent.mm.opensdk.constants.ConstantsAPI;
         没有办法,只能一个一个的改吧。。。
         下一步改AndroidManifest.xml里的包名,改成你的包名
4000

         在改AndroidManifest.xml和Constants文件下为自己的appid如下:
         <data android:scheme=" wx3333"/>
         public static final String APP_ID =" wx3333";
         还的就是把lib下的wechat-sdk-android-with-mta-1.0.2.jar删除的
         注意:还要把项目里的包改为你的包名的“net.sourceforge.simcpux”改为你的包名,同         时AndroidManifest.xml的Activity路径也要改的。       
         因为支付的签名只能为正式的签名,把以我把项目转成AndroidStudio在的项目,在         AndroidStudio里面测试 方法如下:File--Export  一路Next就可以了。



下一步用AndroidStudio打开项目的(该修复的修复一下的,别让项目报错),注意:
         这里也要改的,我的是gradle-3.3-all



#Sat Apr 22 13:17:19 CST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip


配置好正试的签名Gradle文件如下
buildscript {
repositories{
mavenCentral()
}
dependencies{
classpath'com.android.tools.build:gradle:2.3.2'
}
}
apply plugin: 'com.android.application'
dependencies {
compilefileTree(dir: 'libs', include: '*.jar')
}
android {
compileSdkVersion22
buildToolsVersion"25.0.2"
aaptOptions{
cruncherEnabled= false
}
signingConfigs{
//配置签名信息,改为自己的
debug{
storeFile file("key.jks")
storePassword "123456"
keyAlias "lee"
keyPassword "123456"
}
release{
storeFile file("key.jks")
storePassword "123456"
keyAlias "lee"
keyPassword "123456"
}
}
buildTypes{
release{
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'),                               'proguard-rules.pro'
signingConfig signingConfigs.release
}
debug{
signingConfig signingConfigs.debug
}
}
sourceSets{
main{
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
instrumentTest.setRoot('tests')
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
}


         注意:在支付之前,如果应用没有注册到微信,应该先调用         IWXMsg.registerApp  将应用注册到微信。
         然后调用刚才写的支付接口就可以了

try{
String url = "http://192.168.0.112:8080/weipay/prepayid";
byte[]buf = Util.httpGet(url);
if(buf != null && buf.length > 0) {
String content = new String(buf);
Log.e("get server pay params:",content);
JSONObject json = new JSONObject(content);
if(null != json ){
PayReq req = new PayReq();
//req.appId ="wxf8b4f85f3a794e77";  // 测试用appId
req.appId= json.getString("appid");
req.partnerId= json.getString("partnerid");
req.prepayId = json.getString("prepayid");
req.nonceStr = json.getString("noncestr");
req.timeStamp = json.getString("timestamp");
req.packageValue = json.getString("package");
req.sign= json.getString("sign");
req.extData= "app data"; // optional
Toast.makeText(PayActivity.this, "正常调起支付",Toast.LENGTH_SHORT).show();
// 在支付之前,如果应用没有注册到微信,应该先调用  //IWXMsg.registerApp将应用注册到微信
api.sendReq(req);
}else{
Log.d("PAY_GET", "返回错误"+json.getString("retmsg"));
Toast.makeText(PayActivity.this, "返回错误"+json.getString("retmsg"),Toast.LENGTH_SHORT).show();
}
}else{
Log.d("PAY_GET", "服务器请求错误");
Toast.makeText(PayActivity.this, "服务器请求错误",Toast.LENGTH_SHORT).show();
}
}catch(Exception e){
Log.e("PAY_GET","异常:"+e.getMessage());
Toast.makeText(PayActivity.this,"异常:"+e.getMessage(),Toast.LENGTH_SHORT).show();
}


         至于如何写服务器回调就不说了的。(就是微信服务器调后台的接口,然后处理订单状  态),如果App支付过程中返回-1  可能的原因:签名错误、未注册APPID、项目设置  APPID不正确、注册的APPID与设置的不匹配、其他异常等。
         哈哈》》》还有一种情况是如果以上配置都是对,还是一直-1,那么你可以把微信卸了重 装,我的就是这样的,用别人的支付没有问题,我的就不行的,可能是缓存吧。
   /**
* 微信支付签名算法sign
*/
publicstatic String createSign(SortedMap<String, String> parameters) {
StringBuffersb = new StringBuffer();
//所有参与传参的参数按照accsii排序(升序)
Setset = parameters.entrySet();
Iteratorit = set.iterator();
while(it.hasNext()) {
Map.Entryentry = (Map.Entry) it.next();
Stringk = (String) entry.getKey();
Objectv = entry.getValue();
if(null != v && !"".equals(v) &&!"sign".equals(k) && !"key".equals(k)) {
sb.append(k+ "=" + v + "&");
}
}
//重要:这个key是在下面页面配置的--API安全
//https://pay.weixin.qq.com/index.php/core/cert/api_cert
sb.append("key="+ KEY);
Stringsign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
System.out.println("sign:" +sign);
returnsign;
}
项目下载地址http://download.csdn.net/detail/dongliang0108/9844771
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: