忙了整整一天秕重,累的要死厉膀,堅持更新。
以前都是根據(jù)第三方SDK來做支付凳兵,封裝的確實不錯企软,但是自己也是模模糊糊的仗哨,本文只是寫下公眾號的大概支付流程,所以并不會寫太多的代碼萨醒。
1苇倡、首先囤踩,假設(shè)我們已經(jīng)配置好微信授權(quán)目錄,高职,并且假設(shè)授權(quán)目錄為:www.guohe.com
辞州,那么在微信支付頁面需填寫下面的url
:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
解釋:
appid:公眾號id
redirect_uri:后臺支付接口和支付金額变过,例如:www.guohe.com/pay/money=100(必須將此鏈接進行encodeURI編碼)
state:訂單號碼
2、后臺處理支付功能代碼:
在這里除了接收方法中傳進來的金額岛杀、訂單號碼之外崭孤,還需要獲取些微信支付需要的參數(shù),例如公眾號秘鑰和公眾號id等遗锣。
具體如下:
GZHID:微信公眾號id
GZHSecret:微信公眾號密鑰id
SHHID:財付通商戶號
SHHKEY:商戶號對應(yīng)的密鑰
out_trade_no:商戶訂單號
money:金額
code:用戶的code
nonce_str:隨機數(shù)
spbill_create_ip:訂單生成的機器 IP
notify_url:回調(diào)地址
通過code獲取微信用戶的openId和access_token嗤形,工具類:
/**
* 通過微信用戶的code換取網(wǎng)頁授權(quán)access_token
* @return
* @throws IOException
* @throws
*/
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.HYGZHID + "&secret=" + WeChat.HYGZHSecret+ "&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 com.fasterxml.jackson.databind.ObjectMapper.ObjectMapper();
Map<String,Object> jsonOb=mapper.readValue(str, Map.class);
list.add(jsonOb.get("access_token"));
list.add(jsonOb.get("openid"));
}
return list;
}
在這里生成預(yù)支付訂單號的簽名sign:
RequestHandler reqHandler = new RequestHandler(request, response);
reqHandler.init( GZHID, GZHSecret, SHHKEY);
String sign = reqHandler.createSign(packageParams);
生成官方穩(wěn)定xml
數(shù)據(jù):
String xml="<xml>"+
"<appid>"+ GZHID+"</appid>"+
"<mch_id>"+ SHHID+"</mch_id>"+
"<nonce_str>"+nonce_str+"</nonce_str>"+
"<sign>"+sign+"</sign>"+
"<body><![CDATA["+"費用"+"]]></body>"+
"<out_trade_no>"+out_trade_no+"</out_trade_no>"+
"<total_fee>"+finalmoney+"</total_fee>"+
"<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+
"<notify_url>"+notify_url+"</notify_url>"+
"<trade_type>"+trade_type+"</trade_type>"+
"<openid>"+openid+"</openid>"+
"</xml>";
向微信官方統(tǒng)一接口發(fā)送數(shù)據(jù):
String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
String prepay_id="";
try {
prepay_id = GetWxOrderno.getPayNo(createOrderURL, xml);
if(prepay_id.equals("")){
mv.addObject("ErrorMsg", "支付錯誤");
mv.setViewName("error");
return mv;
}
} catch (Exception e) {
logger.error("統(tǒng)一支付接口獲取預(yù)支付訂單出錯", e);
mv.setViewName("error");
return mv;
} else{
mv.addObject("SUCCESS", "支付成功");
mv.setViewName("wechat/pay");
}
3、回調(diào)地址方法的思路只是接收微信通知叶组,并且返回就可以了历造,不然微信會一直發(fā)送通知的,微信發(fā)送的參數(shù)也是一段xml
格式的數(shù)據(jù)枣氧,是需要解析的垮刹,下面是解析工具類张弛,做個記錄:
/**
* description: 解析微信通知xml
*
* @param xml
* @return
*/
@SuppressWarnings({ "unused", "rawtypes", "unchecked" })
private static Map parseXmlToList(String xml) {
Map retMap = new HashMap();
try {
StringReader read = new StringReader(xml);
// 創(chuàng)建新的輸入源SAX 解析器將使用 InputSource 對象來確定如何讀取 XML 輸入
InputSource source = new InputSource(read);
// 創(chuàng)建一個新的SAXBuilder
SAXBuilder sb = new org.jdom.input.SAXBuilder.SAXBuilder();
// 通過輸入源構(gòu)造一個Document
Document doc = (Document) sb.build(source);
Element root = doc.getRootElement();// 指向根節(jié)點
List<Element> es = root.getChildren();
if (es != null && es.size() != 0) {
for (Element element : es) {
retMap.put(element.getName(), element.getValue());
}
}
} catch (Exception e) {
e.printStackTrace();
}
return retMap;
}