思路:首先,由你的支付系統提供一個統一的支付連接入口,將該支付連接生成一個二維碼,用戶經過微信或者支付寶掃該二維碼碼訪問你的支付後臺,支付後臺接收到請求以後,能夠從http請求頭裏獲取use-agent關鍵字信息,APP瀏覽器信息識別關鍵字,若是是支付寶會帶上AlipayClient關鍵字,微信關鍵字爲MicroMessenger,識別了掃碼APP以後,後臺就能夠分別調用支付寶的和微信的支付接口進行支付下單請就OK了。php
具體實現:接下來就是分別選擇那種支付接口比較合適了,當時前先後後也是把螞蟻金服支付文檔和微信的支付文檔擼了好幾遍。支付寶和微信支付的場景都特別的多,例如支付寶:當面付,手機APP支付,網頁支付,h5支付場景,像微信:掃碼支付,APP支付,公衆號支付,最後才肯定採用支付寶的統一收單交易建立接口alipay.trade.create(屬於支付寶當面付接口)和微信的公衆號支付方式來實現後臺的支付下單,接下來就分別詳細說一下微信和支付這兩種支付下單的實現流程css
支付寶:html
一、支付寶網頁受權,獲取支付寶buyer_id,統一收單交易接口須要傳入該字段
前端
2、後臺調用支付寶統一下單接口統一收單交易建立接口,該接口詳情https://docs.open.alipay.com/api_1/alipay.trade.create;該接口將返回支付寶交易號trade_no。jquery
3,將trade_no支付寶交易號等信息該信息傳入前端H5頁面,前端H5使用JSAPI喚起支付寶收銀臺,接下來用戶輸入金額密碼既能夠完成支付操做
web
微信公衆號支付:ajax
一、微信網頁受權、獲取微信用戶openidchrome
二、調用公衆號支付統一下單接口、接口詳情https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1json
三、微信內H5網頁中執行JS調起支付。api
上點代碼吧:
支付入口,識別支付APP
@RequestMapping("pay")
public String wxdemo(HttpServletRequest request) throws Exception {
String useragent = request.getHeader("user-agent");
String payToken = request.getParameter("token");
Order order = orderService.getOrderByToken(payToken);
if(useragent.indexOf("AlipayClient")!= -1){
order.setPaytype(1);
orderService.updateOrder(order);
return "redirect:alipay.html?token="+payToken;
}
/* else if(useragent.indexOf("MicroMessenger")!= -1){
return "redirect:alipay";
}*/
else{
order.setPaytype(2);
orderService.updateOrder(order);
return "redirect:wxpay.html?token="+payToken;
}
}
支付寶支付:
//支付寶網頁受權
}
支付寶支付H5
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="format-detection" content="telephone=no" />
<title>${appname}</title>
<meta name="keywords" content=" " />
<meta name="description" content=" " />
<link rel="stylesheet" type="text/css" href="../css/common.css">
<link rel="stylesheet" type="text/css" href="../css/style.css">
</head>
<body style="overflow-x:hidden;">
<!-- / warpper -->
<div class="phoneCont">
<div class="phoneTitle">
<div class="phonePro">
<ul class="prodetail">
<li><span>商品:</span>${ordername }</li>
<li><span>點單金額:</span>${orderprice }</li>
</ul>
</div>
<div class="proImg">
<img src="../images/procout.jpg" width="100%">
</div>
<div class="proBtn">
<button id="paybtn">當即支付</button>
</div>
</div>
</div>
<!-- / warpper -->
</body>
<script src="../js/jquery-2.1.1.js"></script>
<script>
$(document).ready(function(e) {
if($(window).width()<768){
$('.phoneCont').height($(window).height())
}
});
var orderprice = '${orderprice}';
var ordername = '${ordername}';
var paytoken = '${token}';
function ready(callback) {
// 若是jsbridge已經注入則直接調用
if (window.AlipayJSBridge) {
callback && callback();
} else {
// 若是沒有注入則監聽注入的事件
document.addEventListener('AlipayJSBridgeReady', callback, false);
}
}
ready(function(){
document.querySelector('#paybtn').addEventListener('click', function(){
AlipayJSBridge.call("tradePay", {
tradeNO: '${tradeNo}'
}, function(result) {
var data = JSON.stringify(result)
if(result.resultCode == '9000'){
window.location.href='../success.html?token='+paytoken;
}
});
});
});
</script>
</html>
微信支付
//網頁受權
@RequestMapping(value = "/wxpay")
public String aplipay(HttpServletRequest request)
{
String token = request.getParameter("token");
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+WxPayConstants.APPID+"&redirect_uri="
+"http://crm.xiaowangmao.com/pay/wxauth?token="+token+"&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
return "redirect:"+url;
}
//受權回調,獲取用戶信息
@RequestMapping(value = "/wxauth")
@ResponseBody
public ModelAndView auth(HttpServletRequest request,HttpSession session) throws Exception
{
String token = request.getParameter("token");
System.out.println("進入受權");
ModelAndView mv = new ModelAndView("wxpay");
Order order = orderService.getOrderByToken(token);
mv.addObject("token",token);
mv.addObject("ordername",order.getOrdername());
mv.addObject("orderprice",order.getOrderprice());
mv.addObject("appname",order.getAppname());
String code = request.getParameter("code");
Map authMap = null;
authMap = (Map)session.getAttribute("oauth2Token");
if(authMap == null){
try {
authMap = WxPayUtil.getOpenIdByCode(code);
session.setAttribute("oauth2Token",authMap);
System.out.println("獲取受權openid:"+authMap.get("openid"));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
return mv;
}
/**
* 預支付生成訂單信息
* @param session
* @param request
* @return
*/
@RequestMapping("wxprepay")
@ResponseBody
public String prepay(HttpSession session,HttpServletRequest request){
String res="";
try{
System.out.println("進入預支付");
String token = request.getParameter("token");
System.out.println("微信支付token:"+token);
Order order = orderService.getOrderByToken(token);
System.out.println("weixin支付order信息:"+order.toString());
int total_fee = (int)(order.getOrderprice()*100);
String IP = WxPayUtil.getIpAddr(request);
Map authMap = (Map)session.getAttribute("oauth2Token");
String openid = (String)authMap.get("openid");
Map<String,String> returnMap= WxPayUtil.unifiedOrder(order.getOrdername(), total_fee, IP, openid,order.getOrderid());
Map<String,String> payMap = new HashMap<String,String>();
payMap.put("appId", WxPayConstants.APPID);
payMap.put("nonceStr", WxPayUtil.getNonceStr());
payMap.put("package", "prepay_id="+returnMap.get("prepay_id"));
payMap.put("signType", "MD5");
payMap.put("timeStamp", String.valueOf(System.currentTimeMillis()/1000));
payMap.put("paySign", WxPayUtil.generateSignature(payMap));
JSONObject json = JSONObject.fromObject(payMap);
res = json.toString();
System.out.println("生成預支付訂單信息:"+json.toString());
}catch(Exception e){
e.printStackTrace();
}
return res;
}
/**
* 處理支付異步通知的請求
* @param request
* @param response
* @return
* @throws Exception
*/
@RequestMapping(value ="/wxNotify")
@ResponseBody
public String wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
logger.info("開始處理支付異步通知的請求");
InputStream inputStream;
StringBuffer sb = new StringBuffer();
try {
inputStream = request.getInputStream();
String s ;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null){
sb.append(s);
}
in.close();
inputStream.close();
//解析xml成map
Map<String, String> m = new HashMap<String, String>();
m = WxPayUtil.xmlToMap(sb.toString());
//過濾空 設置 TreeMap
SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();
Iterator it = m.keySet().iterator();
while (it.hasNext()) {
String parameter = (String) it.next();
String parameterValue = m.get(parameter);
String v = "";
if(null != parameterValue) {
v = parameterValue.trim();
}
packageParams.put(parameter, v);
}
// 帳號信息
String out_trade_no = (String)packageParams.get("out_trade_no");
//處理業務開始
//------------------------------
String resXml = "";
Order order = orderService.getOrderByOrderId(out_trade_no);
if("SUCCESS".equals((String)packageParams.get("result_code"))){
order.setStatus(1);
order.setPaytime(DateUtil.date2long(new Date()));
orderService.updateOrder(order);
System.out.println("微信支付回調:支付成功,訂單更新成功");
} else {
order.setStatus(-1);
orderService.updateOrder(order);
System.out.println("支付失敗,錯誤信息:" + packageParams.get("err_code")+
"-----訂單號:::"+out_trade_no+"*******支付失敗時間::::"
+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
String err_code = (String)packageParams.get("err_code");
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[報文爲空]]></return_msg>" + "</xml> ";
}
//------------------------------
//處理業務完畢
//------------------------------
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
return "";
}catch (Exception e){
e.printStackTrace();
return "";
}
}
private String InpuStreamToString(HttpServletRequest request){
BufferedReader reader = null;
StringBuilder sb = new StringBuilder();
String line = null;
try {
reader = request.getReader();
while ((line = reader.readLine()) != null) {
sb.append(line);
sb.append("\r\n");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sb.toString();
}
公衆號h5支付頁面
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta name="renderer" content="webkit"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta name="format-detection" content="telephone=no" /> <title>${appname}</title> <meta name="keywords" content=" " /> <meta name="description" content=" " /> <link rel="stylesheet" type="text/css" href="css/common.css"> <link rel="stylesheet" type="text/css" href="css/style.css"> </head> <body style="overflow-x:hidden;"> <!-- / warpper --> <div class="phoneCont"> <input type="hidden" id="token" value="${token}"> <div class="phoneTitle"> <div class="phonePro"> <ul class="prodetail"> <li><span>商品:</span>${ordername }</li> <li><span>點單金額:</span>${orderprice }</li> </ul> </div> <div class="proImg"> <img src="images/procout.jpg" width="100%"> </div> <div class="proBtn"> <button id="paybtn">當即支付</button> </div> </div> </div> <!-- / warpper --> </body> <script src="js/jquery-2.1.1.js"> </script> <script>$(document).ready(function(e) {if($(window).width()<768){$('.phoneCont').height($(window).height())}});var paytoken = $("#token").val();var appId;var timeStamp;var nonceStr;var packages;var signType;var paySign;$("#paybtn").click(function(){$.ajax({ type:"post",data:{token:paytoken},dataType: "json",async: false,url: "wxprepay", success: function(data){ appId=data.appId; // 支付appId nonceStr=data.nonceStr; // 支付簽名隨機串,不長於32 位 packages=data.package; // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=***) signType="MD5"; // 簽名方式,默認爲'SHA1',使用新版支付需傳入'MD5' paySign=data.paySign; // 支付簽名 timeStamp=data.timeStamp; // 支付時間戳 pay(); },error:function(){alert("生成訂單失敗");}}); });function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId" : appId, //公衆號名稱,由商戶傳入 "timeStamp":timeStamp, //時間戳,自1970年以來的秒數 "nonceStr" : nonceStr, //隨機串 "package" : packages, "signType" : signType, //微信簽名方式: "paySign" : paySign //微信簽名 }, // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回 ok,但並不保證它絕對可靠。 function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) { window.location.href='success.html?token='+paytoken; } }); }function pay(){ if (typeof WeixinJSBridge == "undefined"){if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);}}else{onBridgeReady();}} </script> </html>