微信公众号支付H5调用支付详解
最近项目需要微信支付,然后看了下微信公众号支付,,虽然不难,但是细节还是需要注意的,用了大半天时间写了个demo,并且完整的测试了一下支付流程,下面分享一下微信公众号支付的经验。
一、配置公众号微信支付
需要我们配置微信公众号支付地址和测试白名单。
比如:支付JS页面的地址为 http://www.xxx.com/shop/pay/
那此处配置www.xxx.com/shop/pay/
二、开发流程
借用微信公众号支付api(地址 http://pay.weixin.qq.com/wiki/doc/api/index.PHP?chapter=7_4),我们需要开发的为红色标记出的。如下:
三、向微信服务器端下订单
调用统一下单接口,这样就能获取微信支付的prepay_id(http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=9_1)。
在调用该接口前有几个字段是H5支付必须填写的openid
3.1 获取openid
可以通过网页授权形式(http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html)
在微信中发送如下链接
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=要跳转的下订单的url&response_type=code&scope=snsapi_base&state=123#wechat_redirect
3.2 下订单获取prepay_id
代码如下,实际上是通过post发送一个xml 文件,获取微信服务器端发送过来的prepay_id。
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.gson.oauth.Oauth;
import com.gson.oauth.Pay;
import com.gson.util.HttpKit;
import com.sy.util.DatetimeUtil;
import com.sy.util.JsonUtil;
@Controller
@RequestMapping ( "/pay" )
public class WXPayController {
@RequestMapping (value = "wxprepay.do" )
public void jspay(HttpServletRequest request, HttpServletResponse response, String callback) throws Exception {
String openId = SessionUtil.getAtt(request, "openId" );
if (openId == null ) {
openId = getUserOpenId(request);
}
String appid = "wx16691fcb0523c1a4" ;
String paternerKey = "ININGFENG1234567fdfwfdfd1ss234567" ;
String out_trade_no = getTradeNo();
Map paraMap = new HashMap();
paraMap.put("appid" , appid);
paraMap.put("attach" , "测试" );
paraMap.put("body" , "测试购买支付" );
paraMap.put("mch_id" , "10283271" );
paraMap.put("nonce_str" , create_nonce_str());
paraMap.put("openid" , openId);
paraMap.put("out_trade_no" , out_trade_no);
paraMap.put("spbill_create_ip" , getAddrIp(request));
paraMap.put("total_fee" , "1" );
paraMap.put("trade_type" , "JSAPI" );
paraMap.put("notify_url" , "http://www.xxx.co/bank/page/wxnotify" );
String sign = getSign(paraMap, paternerKey);
paraMap.put("sign" , sign);
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder" ;
String xml = ArrayToXml(paraMap);
String xmlStr = HttpKit.post(url, xml);
String prepay_id = "" ;
if (xmlStr.indexOf( "SUCCESS" ) != - 1 ) {
Map map = doXMLParse(xmlStr);
prepay_id = (String) map.get("prepay_id" );
}
Map payMap = new HashMap();
payMap.put("appId" , appid);
payMap.put("timeStamp" , create_timestamp());
payMap.put("nonceStr" , create_nonce_str());
payMap.put("signType" , "MD5" );
payMap.put("package" , "prepay_id=" + prepay_id);
String paySign = getSign(payMap, paternerKey);
payMap.put("pg" , prepay_id);
payMap.put("paySign" , paySign);
WebUtil.response(response, WebUtil.packJsonp(callback, JsonUtil.warpJsonNodeResponse(JsonUtil.objectToJsonNode(payMap)).toString()));
}
public String ArrayToXml(Map arr) {
String xml = "" ;
Iterator> iter = arr.entrySet().iterator();
while (iter.hasNext()) {
Entry entry = iter.next();
String key = entry.getKey();
String val = entry.getValue();
xml += "<" + key + ">" + val + "" + key + ">" ;
}
xml += "" ;
return xml;
}
private String getUserOpenId(HttpServletRequest request) throws Exception {
String code = request.getParameter("code" );
if (code == null ) {
String openId = request.getParameter("openId" );
return openId;
}
Oauth o = new Oauth();
String token = o.getToken(code);
JsonNode node = JsonUtil.StringToJsonNode(token);
String openId = node.get("openid" ).asText();
return openId;
}
private String create_nonce_str() {
String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ;
String res = "" ;
for ( int i = 0 ; i < 16 ; i++) {
Random rd = new Random();
res += chars.charAt(rd.nextInt(chars.length() - 1 ));
}
return res;
}
private String getAddrIp(HttpServletRequest request){
return request.getRemoteAddr();
}
private String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000 );
}
private String getTradeNo(){
String timestamp = DatetimeUtil.formatDate(new Date(), DatetimeUtil.DATETIME_PATTERN);
return "HZNO" + timestamp;
}
private String getSign(Map params, String paternerKey )
throws UnsupportedEncodingException {
String string1 = Pay.createSign(params, false );
String stringSignTemp = string1 + "&key=" + paternerKey;
String signValue = DigestUtils.md5Hex(stringSignTemp).toUpperCase();
return signValue;
}
private Map doXMLParse(String xml)
throws XmlPullParserException, IOException {
InputStream inputStream = new ByteArrayInputStream(xml.getBytes());
Map map = null ;
XmlPullParser pullParser = XmlPullParserFactory.newInstance()
.newPullParser();
pullParser.setInput(inputStream, "UTF-8" );
int eventType = pullParser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_DOCUMENT:
map = new HashMap();
break ;
case XmlPullParser.START_TAG:
String key = pullParser.getName();
if (key.equals( "xml" ))
break ;
String value = pullParser.nextText();
map.put(key, value);
break ;
case XmlPullParser.END_TAG:
break ;
}
eventType = pullParser.next();
}
return map;
}
}
四、H5支付
H5支付其实很简单,只需要调用微信内嵌浏览器的js方法就行(http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=7_7)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
测试支付
效果如下
转载于:http://blog.csdn.net/u014351782/article/details/52186932