1.需要一个可以登陆微信商户平台的账号,此账号是服务号并开通了微信支付,商户在申请开通时,客服会发送邮件到你的邮箱,
上图中有几个重要信息:商户号和appid,务必记住商户号和appid。其中登陆账号和密码用于登陆微信支付首页点击打开链接
2.点击上图中的下载api证书,设置api密码。这个证书主要在微信支付api中需要证书的地方使用中的退款等功能提示需要证书。
注:什么时候加载使用该证书?当要实现微信退款时,发起退款请求前,需要先加载安全证书
package com.jy.common.pay.weixinpay;
import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
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 ClientCustomSSL {
public static String doRefund(String url, String data) throws Exception {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
URL luj = Thread.currentThread().getContextClassLoader().getResource("apiclient_cert.p12");//src目录下的证书文件
FileInputStream is = new FileInputStream(new File(luj.toURI()));
try {
keyStore.load(is, "这个是你设置的安全证书的密码".toCharArray());// 这里写密码..默认是你的mchid,也就是前面发送给你的
邮件中的商户号
} finally {
is.close();
}
// Trust own CA and all self-signed certs
SSLContext sslcontext = SSLContexts.custom()
.loadKeyMaterial(keyStore, "商户号".toCharArray())// 这里也是写密码的
.build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
try {
HttpPost httpost = new HttpPost(url); // 设置响应头信息
httpost.addHeader("Connection", "keep-alive");
httpost.addHeader("Accept", "*/*");
httpost.addHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
httpost.addHeader("Host", "api.mch.weixin.qq.com");
httpost.addHeader("X-Requested-With", "XMLHttpRequest");
httpost.addHeader("Cache-Control", "max-age=0");
httpost.addHeader("User-Agent","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
httpost.setEntity(new StringEntity(data, "UTF-8"));
CloseableHttpResponse response = httpclient.execute(httpost);
try {
HttpEntity entity = response.getEntity();
String jsonStr = EntityUtils.toString(response.getEntity(),
"UTF-8");
EntityUtils.consume(entity);
return jsonStr;
} finally {
response.close();
}
} finally {
httpclient.close();
}
}
}
上面返回的jsonStr则是:你发起退款时返回的一些json信息,这里一般将其转为map方便使用。
其中上面调用的方法需要2个参数:url,data
url:微信支付提供的退款接口https://api.mch.weixin.qq.com/secapi/pay/refund
data:这个参数微信支付官方推荐使用xml格式,所以一般都是用String字符串构造一个xml,这个xml和官方文档一样
<xml>
<appid>wx2421b1c4370ec43b</appid>
<mch_id>10000100</mch_id>
<nonce_str>6cefdb308e1e2e8aabd48cf79e546a02</nonce_str>
<out_refund_no>1415701182</out_refund_no>
<out_trade_no>1415757673</out_trade_no>
<refund_fee>1</refund_fee>
<total_fee>1</total_fee>
<transaction_id></transaction_id>
<sign>FE56DD4AA85C0EECA82C35595A69E153</sign>
</xml>
data就是上面这个xml的字符串,一般先将退款接口需要的参数放入到map中,在将map转为xml字符串。
3.在实现预支付订单前应先获取到开发需要的一些参数:如openid、随机字符串、签名、
1.openid获取:
String url="https://api.weixin.qq.com/sns/oauth2/access_token?"
+ "appid="+你的appid+ "&secret="+你的secret
+ "&code="+code
+ "&grant_type=authorization_code";
JSONObject jsonObject=HttpGet.getRes(url);
String usersWeixinId=jsonObject.getString("openid");
secret是公众号的appsecret,这个在微信支付平台中的开发者中心可以找到
code是应用授权作用域,官方提供两个,任选一个:snsapi_base(不弹出授权窗口,只获取openid),snsapi_userinfo(弹出授权窗口.....)
2.随机字符串获取:这个参数一般是32位以内的大写字母和0-9数字的随机组合,不能超出32位
3.签名获取:签名详细算法地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3
获取签名步骤:
根据上图中的参数生成字符串
stringA="appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA";
再接着串联:
stringSignTemp=stringA+"&key=192006250b4c09247ec02edce69f6a2d" //注:key为商户平台设置的密钥key
sign=MD5(stringSignTemp).toUpperCase()="9A0A8659F005D6984697E2CA0A9CF3B7" //注:MD5签名方式
sign=hash_hmac("sha256",stringSignTemp,key) //注:HMAC-SHA256签名方式
两种签名方式任选,sign这就是我们需要的签名
4.简单地说:实现微信支付中的各种功能只需要3个大步骤:1.微信公众号支付的各个接口。2.生成发起订单等功能的XML字符串。3.发送http请求,输出返回的结果
1.预支付订单接口:https://api.mch.weixin.qq.com/pay/unifiedorder
预支付订单的通知地址:http://www.weixin.qq.com/wxpay/pay.php(即发起订单后的回调接口),此接口不能携带参数
2.查询预支付订单的接口:https://api.mch.weixin.qq.com/pay/orderquery
查询预支付订单时需要一个参数:微信订单号或者商户订单号任选一个,一般优先微信订单号,商户订单号的详细算法地址:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_2,就是拼接各个参数
这两个订单号的详细资料地址:http://www.tuicool.com/articles/vIFR7rJ
3.关闭订单接口:https://api.mch.weixin.qq.com/pay/closeorder
4.申请退款接口:https://api.mch.weixin.qq.com/secapi/pay/refund 此功能需要安全证书,自己去开发者中心下载
退款接口中需要的商户订单号与商户退款订单号是一致的,主要实现:
public
static
String getRandomStringByLength(
int
length) {
String base =
"0123456789"
;
Random random =
new
Random();
StringBuffer sb =
new
StringBuffer();
for
(
int
i =
0
; i < length; i++) {
int
number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return
sb.toString();
}
/**
* @function 生成商户订单号/退款单号
* @date 2015-12-17
* @return String
*/
public
static
String getOrderNo(){
SimpleDateFormat sdf =
new
SimpleDateFormat(
"yyyyMMddHHmmssSSS"
);
Date date =
new
Date();
return
sdf.format(date) + getRandomStringByLength(
4
);
}
5.查询退款接口:https://api.mch.weixin.qq.com/pay/refundquery
6.下载对账单:https://api.mch.weixin.qq.com/pay/downloadbill
7.支付结果通知:https://pay.weixin.qq.com/wxpay/pay.action或者http://www.weixin.qq.com/wxpay/pay.php
8.获取openid接口:https://api.weixin.qq.com/sns/oauth2/access_token需要部分参数,上面有例子