思路:首先,由你的支付系统提供一个统一的支付链接入口,将该支付链接生成一个二维码,用户通过微信或者支付宝扫该二维码码访问你的支付后台,支付后台接收到请求之后,可以从http请求头里获取use-agent关键字信息,APP浏览器信息识别关键字,如果是支付宝会带上AlipayClient关键字,微信关键字为MicroMessenger,识别了扫码APP之后,后台就可以分别调用支付宝的和微信的支付接口进行支付下单请就OK了。
具体实现:接下来就是分别选择那种支付接口比较合适了,当时前前后后也是把蚂蚁金服支付文档和微信的支付文档撸了好几遍。支付宝和微信支付的场景都特别的多,例如支付宝:当面付,手机APP支付,网页支付,h5支付场景,像微信:扫码支付,APP支付,公众号支付,最后才确定采用支付宝的统一收单交易创建接口alipay.trade.create(属于支付宝当面付接口)和微信的公众号支付方式来实现后台的支付下单,接下来就分别详细说一下微信和支付这两种支付下单的实现流程
支付宝:
1、支付宝网页授权,获取支付宝buyer_id,统一收单交易接口需要传入该字段
2、后台调用支付宝统一下单接口统一收单交易创建接口,该接口详情https://docs.open.alipay.com/api_1/alipay.trade.create;该接口将返回支付宝交易号trade_no。
3,将trade_no支付宝交易号等信息该信息传入前端H5页面,前端H5使用JSAPI唤起支付宝收银台,接下来用户输入金额密码既可以完成支付操作
微信公众号支付:
1、微信网页授权、获取微信用户openid
2、调用公众号支付统一下单接口、接口详情https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
3、微信内H5网页中执行JS调起支付。
上点代码吧:
支付入口,识别支付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;
}
}
支付宝支付:
//支付宝网页授权
@RequestMapping(value = "/alipay")
public String aplipay(HttpServletRequest request)
{
String token = request.getParameter("token");
String url = "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id="+AlipayConfig.APPID+"&scope=auth_base&redirect_uri=http://crm.xiaowangmao.com/pay/aplipay/auth?token="+token;
return "redirect:"+url;
}
//网页授权回调,获取用户信息,调用统一收单交易接口创建订单,将订单信息传h5页面,h5页面唤起支付收银台
@RequestMapping(value = "/aplipay/auth")
public ModelAndView auth(HttpServletRequest request)
{
String token = request.getParameter("token");
ModelAndView mv = new ModelAndView("alipay");
String auth_code = request.getParameter("auth_code");
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, "json", AlipayConfig.charset, AlipayConfig.ALIPAY_PUBLIC_KEY, "RSA2");
AlipaySystemOauthTokenRequest authRequest = new AlipaySystemOauthTokenRequest();
authRequest.setCode(auth_code);
authRequest.setGrantType("authorization_code");
try {
AlipaySystemOauthTokenResponse oauthTokenResponse = alipayClient.execute(authRequest);
String userId = oauthTokenResponse.getUserId();
System.out.println("alipay支付token:"+token);
Order order = orderService.getOrderByToken(token);
System.out.println("alipay支付order信息:"+order.toString());
String tradeNo = createOrder(userId,order);
System.out.println("支付宝支付交易号tradeNo:"+tradeNo);
order.setTrade_no(tradeNo);
orderService.updateOrder(order);
mv.addObject("token",token);
mv.addObject("tradeNo",tradeNo);
mv.addObject("ordername",order.getOrdername());
mv.addObject("orderprice",order.getOrderprice());
mv.addObject("appname",order.getAppname());
} catch (AlipayApiException e) {
//处理异常
e.printStackTrace();
}
return mv;
}
//创建订单
private String createOrder(String userId,Order order){
String tradeNo = "";
try{
String notify_url = "http://crm.xiaowangmao.com/pay/aliNotify";
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY,
"json", AlipayConfig.charset, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);
AlipayTradeCreateRequest aplipayRequest = new AlipayTradeCreateRequest();
aplipayRequest.setNotifyUrl(notify_url);
aplipayRequest.setBizContent("{\"out_trade_no\":\""+order.getOrderid()+"\",\"buyer_id\":\""+userId+"\",\"total_amount\":\""+order.getOrderprice()+"\",\"notify_url\":\""+notify_url+"\",\"subject\":\""+order.getOrdername()+"\"}");
AlipayTradeCreateResponse response = null;
try {
response = alipayClient.execute(aplipayRequest);
} catch (AlipayApiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(response.isSuccess()){
tradeNo = response.getTradeNo();
System.out.println("调用成功");
} else {
System.out.println("调用失败:"+response.getBody());
}
}catch (Exception e){
e.printStackTrace();
}
return tradeNo;
}
//支付结果异步回掉,没有做签名验证
@RequestMapping(value = "/aliNotify")
@ResponseBody
public String notify(HttpServletRequest request) throws UnsupportedEncodingException, AlipayApiException {
System.out.println("进入阿里支付回掉");
Map<String,String> params = this.getParams(request);
Order order = null;
//商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
order = orderService.getOrderByOrderId(out_trade_no);
if(order.getStatus() != 0){
return "";
}
System.out.println("支付产品交易号:"+trade_no);
//交易状态
String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");
try{
if (trade_status.equals("TRADE_SUCCESS")){
System.out.println("支付宝回调支付成功:");
order.setStatus(1);
}else{
System.out.println("支付宝回调支付失败:");
order.setStatus(-1);
}
}catch(Exception e){
e.printStackTrace();
}
order.setPaytime(DateUtil.date2long(new Date()));
orderService.updateOrder(order);
return "alipaySuccess";
}
private Map<String,String> getParams(HttpServletRequest request){
Map<String,String> params = new HashMap<String,String>();
try{
Map<String,String[]> requestParams = request.getParameterMap();
for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
}catch (Exception e){
e.printStackTrace();
}
return params;
}
支付宝支付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>