要实现微信支付要满足几个条件:
一、有一个服务号,菜单栏里面有微信支付菜单的公众号
常用的几个参数 下面例子参数值已经经过处理
public final class WxConfig {
public final static String appId = "wx98dc29047cexxxx"; // 公众号appid
public final static String mchId = "1566911111";// 商户ID
public final static String key = "xxxxxxx4TI4srY33SwkyXYojBzK6Fsp"; // 商户KEY 跟微信支付约定的密钥
public final static String payUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder"; // 统一下单地址
public final static String tradeType = "JSAPI"; // 支付方式
public final static String secret="xxx9b86bdb6637a4ccfaf6e7e2609";//商户APPSECRET
}
以下是微信支付流程,后面会根据流程上响应的代码
微信工具包下载,其中很多类可以使用
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
https://open.weixin.qq.com/connect/oauth2/authorize
var code = getUrlParam('code') // 截取路径中的code,如果没有就去微信授权,如果已经获取到了就直接传code给后台获取openId
var local = window.location.href
if (code == null || code === '') {
window.location.href = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx98dc29047xxxxx&redirect_uri=' + encodeURIComponent(local) +'&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect'
}
中间有几个参数
微信会通过回调的方式跳回原来的页面,code就是用户的会话ID了,某个时段有效。
redirect_uri/?code=CODE&state=STATE
https://api.weixin.qq.com/sns/oauth2/access_token
拿到code以后为了安全性提交到后台,后台我这里是用的java springboot框架
String code = json.get("code").toString();
String res = get("https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + WxConfig.appId + "&secret="+ WxConfig.secret + "&code=" + code + "&grant_type=authorization_code");
JSONObject json1 = JSONObject.parseObject(res);
String openId = json1.getString("openid");
System.out.println(openId+"------------------------------");
这里使用的 WxConfig 就是文章开头的配置文件类
public String get(String url) throws Exception {
// 创建HttpClient实例
CloseableHttpClient client = HttpClientBuilder.create().build();
// 根据URL创建HttpGet实例
HttpGet get = new HttpGet(url);
// 执行get请求,得到返回体
HttpResponse response = client.execute(get);
// 判断是否正常返回
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
// 解析数据
String data = EntityUtils.toString(response.getEntity(), Charsets.UTF_8);
System.out.println(data);
return data;
}
return "";
}
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<version>4.5.3version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.3version>
dependency>
https://api.mch.weixin.qq.com/pay/unifiedorder
拿到openId以后就可以发起订单了
@RequestMapping("/payH5")
@ResponseBody
public Object payH5(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, Object> json)
throws Exception {
try {
String orderNo = UUID.randomUUID().toString().replaceAll("-", "");
//记得自己把订单id保存下来 orderNo
String code = json.get("code").toString();
String res = get("https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + WxConfig.appId + "&secret="
+ WxConfig.secret + "&code=" + code + "&grant_type=authorization_code");
JSONObject json1 = JSONObject.parseObject(res);
String openId = json1.getString("openid"); //获取的用户唯一标识
System.out.println(openId+"------------------------------");
Map<String, String> paraMap = new HashMap<>();
paraMap.put("appid", WxConfig.appId);//公众号appid
paraMap.put("body", json.get("body").toString());//商品说明
paraMap.put("mch_id", WxConfig.mchId);//商家id
paraMap.put("nonce_str", WXPayUtil.generateNonceStr());
paraMap.put("openid", openId);
paraMap.put("out_trade_no", orderNo);
paraMap.put("spbill_create_ip", "120.79.1.1");
paraMap.put("total_fee", String.valueOf((int)(Double.parseDouble(kc.getSpjg())*100)));
paraMap.put("trade_type", WxConfig.tradeType);
paraMap.put("notify_url","http://yunkt.zmxzc.com//api/wxnotify");
String apiKey = WxConfig.key;
System.out.println(WXPayUtil.mapToXml(paraMap));
String sign = WXPayUtil.generateSignature(paraMap, apiKey);
paraMap.put("sign", sign);
String xml = WXPayUtil.mapToXml(paraMap);
System.out.println(xml);
// 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
String xmlStr = WXPayReport.httpRequest(unifiedorder_url, xml, 2000, 5000);
// 以下内容是返回前端页面的json数据
System.out.println(xmlStr);
String prepay_id = "";// 预支付id
if (xmlStr.indexOf("SUCCESS") != -1) {
Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
prepay_id = (String) map.get("prepay_id");
}
Map<String, String> payMap = new HashMap<String, String>();
payMap.put("appId", WxConfig.appId);
payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
payMap.put("nonceStr", WXPayUtil.generateNonceStr());
payMap.put("signType", "MD5");
payMap.put("package", "prepay_id=" + prepay_id);
String paySign = WXPayUtil.generateSignature(payMap, WxConfig.key);
payMap.put("paySign", paySign);
payMap.put("orderNo", orderNo);
payMap.put("success", "0");
return payMap;
} catch (Exception e) {
e.printStackTrace();
Map<String, String> payMap = new HashMap<String, String>();
payMap.put("success", "1");
return payMap;
}
// return new SuccessResponseData();
}
httpRequest 方法改写新增了 WXPayReport工具包中 的请求方法
public static String httpRequest(String url,String data, int connectTimeoutMs, int readTimeoutMs) throws Exception{
BasicHttpClientConnectionManager connManager;
connManager = new BasicHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build(),
null,
null,
null
);
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connManager)
.build();
HttpPost httpPost = new HttpPost(url);
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(readTimeoutMs).setConnectTimeout(connectTimeoutMs).build();
httpPost.setConfig(requestConfig);
StringEntity postEntity = new StringEntity(data, "UTF-8");
httpPost.addHeader("Content-Type", "text/xml");
httpPost.addHeader("User-Agent", WXPayConstants.USER_AGENT);
httpPost.setEntity(postEntity);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
return EntityUtils.toString(httpEntity, "UTF-8");
}
payMap 返回的值就是我们调用支付所需要的参数的,所有的工作就是为了获取这些
4、调用微信支付,必须在微信内置浏览器,不然会失败
WeixinJSBridge.invoke('getBrandWCPayRequest', {
"appId": data.appId, //公众号名称,由商户传入
"timeStamp": data.timeStamp, //时间戳,自1970年以来的秒数
"nonceStr": data.nonceStr, //随机串
"package": data.package,
"signType": data.signType, //微信签名方式:
"paySign": data.paySign //微信签名
}, function(res) {
console.log(res);
//window.location.href = local
if (res.err_msg == "get_brand_wcpay_request:ok") {
alert('支付成功');
window.location.href =localStorage.getItem('location');
} else if (res.err_msg == "get_brand_wcpay_request:cancel") {
alert('支付取消');
window.location.href =localStorage.getItem('location');
} else if (res.err_msg == "get_brand_wcpay_request:fail") {
alert('支付失败');
window.location.href =localStorage.getItem('location');
}else{
alert('支付异常');
window.location.href =localStorage.getItem('location');
}
})
5、查询订单支付状态
Map<String, String> paraMap = new HashMap<>();
paraMap.put("appid", WxConfig.appId);
paraMap.put("mch_id", WxConfig.mchId);
paraMap.put("nonce_str", WXPayUtil.generateNonceStr());
paraMap.put("out_trade_no", f.getDdid());//前面的 String orderNo = UUID.randomUUID().toString().replaceAll("-", "");
paraMap.put("spbill_create_ip", "120.79.1.1");
String apiKey = WxConfig.key;
String sign = WXPayUtil.generateSignature(paraMap, apiKey);
paraMap.put("sign", sign);
String xml = WXPayUtil.mapToXml(paraMap);
System.out.println(xml);
// 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/orderquery";
String xmlStr = WXPayReport.httpRequest(unifiedorder_url, xml, 2000, 5000);
// 以下内容是返回前端页面的json数据
System.out.println(xmlStr);
if (xmlStr.indexOf("SUCCESS") != -1) {
Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
if(map.get("trade_state")!=null&&((String) map.get("trade_state")).equals("SUCCESS")){
//修改本地订单状态
//这里的订单就是前面的String orderNo = UUID.randomUUID().toString().replaceAll("-", "");
}
}
<xml>
<return_code>return_code>
<return_msg>return_msg>
<appid>appid>
<mch_id>mch_id>
<device_info>device_info>
<nonce_str>nonce_str>
<sign>sign>
<result_code>result_code>
<openid>openid>
<is_subscribe>is_subscribe>
<trade_type>trade_type>
<bank_type>bank_type>
<total_fee>1total_fee>
<fee_type>fee_type>
<transaction_id>transaction_id>
<out_trade_no>out_trade_no>
<attach>attach>
<time_end>time_end>
<trade_state>trade_state>
xml>
这里整个流程就结束了。