申请公众号商户号和开发者平台账号这个就不用说了吧。
拿到参数有三个:
参数名 | 描述 |
---|---|
appid | 公众账号ID |
mch_id | 商户号 |
secret | 公众号秘钥 |
统一下单需要参数示例(官方给出示例)
<xml>
<appid>wx2421b1c4370ec43bappid>
<attach>支付测试attach>
<body>JSAPI支付测试body>
<mch_id>10000100mch_id>
<detail>detail>
<nonce_str>1add1a30ac87aa2db72f57a2375d8fecnonce_str>
<notify_url>http://wxpay.wxutil.com/pub_v2/pay/notify.v2.phpnotify_url>
<openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6oopenid>
<out_trade_no>1415659990out_trade_no>
<spbill_create_ip>14.23.150.211spbill_create_ip>
<total_fee>1total_fee>
<trade_type>JSAPItrade_type>
<sign>0CB01533B8C1EF103065174F50BCA001sign>
xml>
var url="<%=path%>XXX/wechat/pay.do?orderId="+orderId; //这里不可以带端口号:80这种,不然前端会报10003错误
var weixinUrl="https://open.weixin.qq.com/connect/oauth2/authorize?appid=app_id&redirect_uri="+url+"&response_type=code&scope=snsapi_userinfo&state="+orderId+"#wechat_redirect";
window.location.href=encodeURI(weixinUrl);
url是你的地址可以是获取openid的接口,也可以是直接下单接口,如果是直接下单的接口那么获取openid就的和生成预订单时一起获取.
后端获取openid
public List<Object> accessToken(String code) throws IOException {
List<Object> list = new ArrayList<Object>();
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="
+ WeChat.APPID + "&secret=" + WeChat.secret + "&code="
+ code + "&grant_type=authorization_code";
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
HttpResponse res = client.execute(post);
if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity entity = res.getEntity();
String str = org.apache.http.util.EntityUtils.toString(entity,
"utf-8");
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> jsonOb = mapper.readValue(str, Map.class);
list.add(jsonOb.get("access_token"));
list.add(jsonOb.get("openid"));
}
return list;
}
获取到access_token和openid
统一下单接口
url:https://api.mch.weixin.qq.com/pay/unifiedorder
String nonce_str = MD5Util.MD5Encode(String.valueOf(SnowflakeIdUtil.getSnowflakeId()), "UTF-8");
// 订单生成的机器 IP
String spbill_create_ip = request.getRemoteAddr();
// 交易类型 :jsapi代表微信公众号支付
String trade_type = "JSAPI";
// 这里notify_url是 微信处理完支付后的回调的应用系统接口url。
String url= request.getRequestURL().toString().substring(0, url.lastIndexOf("/")+1);
//生产环境
String notify_url= url+"weixinNotify.do";
//组装参数
SortedMap
这里我用的是自己写的签名方法,官方Demo中有生成签名的方法
public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();
Iterator it = es.iterator();
List<String> list = new ArrayList<String>();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String k = (String)entry.getKey();
list.add(k);
}
Collections.sort(list);
for(String str : list){
Object v = parameters.get(str);
if(null != v && !"".equals(v) && !"sign".equals(str) && !"key".equals(str)) {
sb.append(str + "=" + v + "&");
}
}
sb.append("key="+"这里是开发配置的key");//需要自己生成并填写到开发配置中
String stringSignTemp = sb.toString();
String sign = MD5Util.MD5Encode(stringSignTemp, characterEncoding).toUpperCase();
return sign;
}
生成xml并请求预订单
String requestXML = PayCommonUtil.getRequestXml(packageParams); //将Map集合转换为XMl
String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
String result = PayCommonUtil.httpsRequest(createOrderURL, "POST", requestXML);
Map<String, String> resultMap = XMLUtil.doXMLParse(result);//将XML转换为Map集合
String prepay_id = resultMap .get("prepay_id");
文中出现的工具类官方demo中基本都有,没有的话自己写一个也就好了
如果能获取到prepay_id 那么你就基本上可以happy一下了
组装调起微信支付的参数列表
SortedMap finalpackage = new TreeMap();
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);//时间戳
String packages = "prepay_id="+prepay_id;//这里需要特别注意下,package是关键字,尴尬!-_-
finalpackage.put("appId", WeChat.GZHAPPID);//这里注意一下,appId是大写的I
finalpackage.put("timeStamp", timestamp);
finalpackage.put("nonceStr", nonce_str);
finalpackage.put("package", packages);
finalpackage.put("signType", "MD5");
Map mv = new HashedMap<>();
mv.put("appId", WeChat.GZHAPPID);
mv.put("timeStamp", timestamp);
mv.put("nonceStr", nonce_str);
mv.put("packageStr", packages);
mv.put("signType", "MD5");
mv.put("paySign", PayCommonUtil.createSign("UTF-8",finalpackage));//获取二次签名
mv.put("success","ok");
mv.put("orderId",out_trade_no);
mv.put("payPrice",payPrice);
ok
返回前端唤起微信支付吧
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":appId, //公众号名称,由商户传入
"paySign":paySign, //微信签名
"timeStamp":timeStamp, //时间戳,自1970年以来的秒数
"nonceStr":nonceStr , //随机串
"package":packageStr, //预支付交易会话标识
"signType":signType //微信签名方式
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
alert('支付成功');
}else if(res.err_msg == "get_brand_wcpay_request:cancel"){
alert('支付取消');
}else if(res.err_msg == "get_brand_wcpay_request:fail" ){
alert('支付失败');
} //使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
}
);
支付成功后回调
@RequestMapping(value="/weixinNotify.do")
public void weixinNotify(HttpServletRequest request, HttpServletResponse response){
String out_trade_no=null;
String return_code =null;
try {
InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
outSteam.close();
inStream.close();
String resultStr = new String(outSteam.toByteArray(),"utf-8");
logger.info("支付成功的回调:"+resultStr);
Map<String, Object> resultMap = XMLUtil.doXMLParse(resultStr);
//下面这些参数需要的可以获取,不需要也可以不用获取
String result_code = (String) resultMap.get("result_code");
String is_subscribe = (String) resultMap.get("is_subscribe");
String transaction_id = (String) resultMap.get("transaction_id");
String sign = (String) resultMap.get("sign");
String time_end = (String) resultMap.get("time_end");
String bank_type = (String) resultMap.get("bank_type");
out_trade_no = (String) resultMap.get("out_trade_no");
return_code = (String) resultMap.get("return_code");
request.setAttribute("out_trade_no", out_trade_no);
//通知微信.异步确认成功.必写.不然微信会一直通知后台.八次之后就认为交易失败了.
response.getWriter().write(RequestHandler.setXML("SUCCESS", ""));
} catch (Exception e) {
logger.error("微信回调接口出现错误:",e);
try {
response.getWriter().write(RequestHandler.setXML("FAIL", "error"));
} catch (IOException e1) {
e1.printStackTrace();
}
}
if(return_code.equals("SUCCESS")){
//支付成功的业务逻辑
}else{
//支付失败的业务逻辑
}
}
微信公众号官方文档大家可以看看,也可以吐槽。
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
微信官方给出参数的详细说明。
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
如果文中有什么不对的,或者有什么问题,可以直接留言.欢迎指正!