h5 页面在微信浏览器里调用支付接口 ,写的一个测试的支付流程,比较乱,望勿吐槽。
简要代码如下
前端
1、准备
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
onBridgeReady();
}else{
onBridgeReady();
}
function onBridgeReady(){
window.location.href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=*******&redirect_uri=域名/wx/restf/np-pay-getOpenId?orderId="+$("#mergeId").val()+"&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
}
3、拿到openId 获取微信交互权限
@RequestMapping("np-pay-getOpenId")
public String getOpenId(Model model,HttpServletRequest request) {
String code = request.getParameter("code");
String orderId = request.getParameter("orderId");
PersonOrder order = null;
NpShop shop = null;
double totalPrice = 0.0;
List<PersonOrderMerge> personOrderMerges = null;
if(StringHelper.isNotEmpty(orderId)) {
personOrderMerges = personOrderMergeManager.findBy("parentId", orderId);
if(personOrderMerges!=null) {
for(PersonOrderMerge pom:personOrderMerges) {
order = personOrderManager.findUniqueBy("id", pom.getOrderId());
shop = shopManager.findUniqueBy("id", order.getShopId());
totalPrice = totalPrice+order.getTotalPrice();
}
}
}
//获取opendId
String openId = request.getSession().getAttribute("openId")==null?null:request.getSession().getAttribute("openId")+"";
String accessTocken = request.getSession().getAttribute("accessTocken")==null?null:request.getSession().getAttribute("accessTocken")+"";
String ticket = request.getSession().getAttribute("ticket")==null?null:request.getSession().getAttribute("ticket")+"";
if(StringHelper.isNotEmpty(code)&&StringHelper.isEmpty(openId)) {
//https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ConfigUtil.APPID+"&secret="+ConfigUtil.APP_SECRECT+"&code="+code+"&grant_type=authorization_code";
String result = CommonUtil.httpsRequest(requestUrl, "POST", null);
//System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++"+result);
if(result!=null) {
JSONArray jsonArray = JSONArray.fromObject("["+result+"]");
List<Map<String,Object>> mapListJson = (List)jsonArray;
for (int i = 0; i < mapListJson.size(); i++) {
Map<String,Object> obj=mapListJson.get(i);
for(Entry<String,Object> entry : obj.entrySet()){
String strkey1 = entry.getKey();
Object strval1 = entry.getValue();
System.out.println("KEY:"+strkey1+" --> Value:"+strval1+"\n");
if("openid".equals(strkey1)) {
openId = strval1+"";
request.getSession().setAttribute("openId", openId);
request.getSession().setMaxInactiveInterval(7000);
}
}
}
}
}
if(StringHelper.isEmpty(accessTocken)) {
String requestUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+ConfigUtil.APPID+"&secret="+ConfigUtil.APP_SECRECT;
String result = CommonUtil.httpsRequest(requestUrl, "GET", null);
if(result!=null) {
JSONArray jsonArray = JSONArray.fromObject("["+result+"]");
List<Map<String,Object>> mapListJson = (List)jsonArray;
for (int i = 0; i < mapListJson.size(); i++) {
Map<String,Object> obj=mapListJson.get(i);
for(Entry<String,Object> entry : obj.entrySet()){
String strkey1 = entry.getKey();
Object strval1 = entry.getValue();
System.out.println("KEY:"+strkey1+" --> Value:"+strval1+"\n");
if("access_token".equals(strkey1)) {
accessTocken = strval1+"";
request.getSession().setAttribute("accessTocken", accessTocken);
request.getSession().setMaxInactiveInterval(7000);
}
}
}
}
}
if(StringHelper.isNotEmpty(accessTocken)&&StringHelper.isEmpty(ticket)) {
String requestUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+accessTocken+"&type=jsapi";
String result = CommonUtil.httpsRequest(requestUrl, "GET", null);
if(result!=null) {
JSONArray jsonArray = JSONArray.fromObject("["+result+"]");
List<Map<String,Object>> mapListJson = (List)jsonArray;
for (int i = 0; i < mapListJson.size(); i++) {
Map<String,Object> obj=mapListJson.get(i);
for(Entry<String,Object> entry : obj.entrySet()){
String strkey1 = entry.getKey();
Object strval1 = entry.getValue();
System.out.println("KEY:"+strkey1+" --> Value:"+strval1+"\n");
if("ticket".equals(strkey1)) {
ticket = strval1+"";
request.getSession().setAttribute("ticket", ticket);
request.getSession().setMaxInactiveInterval(7000);
}
}
}
}
}
//下单参数
SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();
parameters.put("appid", ConfigUtil.APPID);
parameters.put("mch_id", ConfigUtil.MCH_ID);
parameters.put("nonce_str", PayCommonUtil.CreateNoncestr());
parameters.put("body", shop==null?"":shop.getTitle());
parameters.put("out_trade_no", orderId);
parameters.put("total_fee", Integer.parseInt(new java.text.DecimalFormat("0").format(totalPrice*100))+"");
String Ip = IpAddressUtil.getIpAddr(request);
if(Ip!=null) {
Ip = Ip.split(",")[0];
}
parameters.put("spbill_create_ip",Ip);
parameters.put("notify_url", ConfigUtil.NOTIFY_URL);
parameters.put("trade_type", "JSAPI");
parameters.put("openid", openId);
String sign = PayCommonUtil.createSign("UTF-8", parameters);
parameters.put("sign", sign);
String requestXML = PayCommonUtil.getRequestXml(parameters);
String result =CommonUtil.httpsRequest(ConfigUtil.UNIFIED_ORDER_URL, "POST", requestXML);
try {
Map<String, String> map = XMLUtil.doXMLParse(result);
SortedMap<Object,Object> params = new TreeMap<Object,Object>();
String timeStamp = Long.toString(new Date().getTime());
String nonceStr = PayCommonUtil.CreateNoncestr();
params.put("appId", ConfigUtil.APPID);
params.put("timeStamp",timeStamp);
params.put("nonceStr", nonceStr);
params.put("package", "prepay_id="+map.get("prepay_id"));
params.put("signType", ConfigUtil.SIGN_TYPE);
String paySign = PayCommonUtil.createSign("UTF-8", params);
params.put("packageValue", "prepay_id="+map.get("prepay_id")); //这里用packageValue是预防package是关键字在js获取值出错
params.put("paySign", paySign); //paySign的生成规则和Sign的生成规则一致
params.put("sendUrl", ConfigUtil.SUCCESS_URL); //付款成功后跳转的页面
String userAgent = request.getHeader("user-agent");
char agent = userAgent.charAt(userAgent.indexOf("MicroMessenger")+15);
params.put("agent", new String(new char[]{agent}));//微信版本号,用于前面提到的判断用户手机微信的版本是否是5.0以上版本。
model.addAttribute("appId", ConfigUtil.APPID);
model.addAttribute("timeStamp", timeStamp);
model.addAttribute("nonceStr", nonceStr);
model.addAttribute("package", "prepay_id="+map.get("prepay_id"));
model.addAttribute("signType", ConfigUtil.SIGN_TYPE);
model.addAttribute("packageValue", "prepay_id="+map.get("prepay_id"));
model.addAttribute("paySign", paySign);
model.addAttribute("sendUrl", ConfigUtil.SUCCESS_URL);
model.addAttribute("agent", new String(new char[]{agent}));
model.addAttribute("orderId", orderId);
SortedMap<Object,Object> parameters_ = new TreeMap<Object,Object>();
parameters_.put("jsapi_ticket", ticket);
parameters_.put("timestamp", timeStamp);
parameters_.put("noncestr", nonceStr);
parameters_.put("url", getFullURL(request));
String signature = PayCommonUtil.getSignature(parameters_);
model.addAttribute("signature", signature);
// String json = JSONObject.fromObject(params).toString();
} catch (JDOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//解析微信返回的信息,以Map形式存储便于取值
return "h5/wx/topay";
}
4、跳转到前端页面 调用支付控件
<script src="${ctx }/assets/goods/js/jquery.min.js"></script>
<script type="text/javascript" charset="UTF-8" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script type="text/javascript">
function pay(){
var appId = $('#appId').val();
var timeStamp = $('#timeStamp').val();
var nonceStr = $('#nonceStr').val();
var pk = $('#package').val();
var signType = $('#signType').val();
var paySign = $('#paySign').val();
//config
var signature = $('#signature').val();
var activityId = $('#activityId').val();
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: appId, // 必填,公众号的唯一标识
timestamp:timeStamp, // 必填,生成签名的时间戳
nonceStr: nonceStr, // 必填,生成签名的随机串
signature: signature,// 必填,签名,见附录1
jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.ready(function(){
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
wx.chooseWXPay({
timestamp: timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: nonceStr, // 支付签名随机串,不长于 32 位
package: pk, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
signType: signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: paySign, // 支付签名
complete: function (res) {
// 支付成功后的回调函数
//location.href=basePath+'/activityorder/activity-order!list.action?activityId='+activityId;
if(res.errMsg=="chooseWXPay:ok"){
$.ajax({
url: "${ctx}/np/restf/person/np-orders-merge-update",
data:{mergeId:$("#mergeId").val()},
dataType: "json",
async: false,
type: 'POST',
success: function(data){
window.location.href="${ctx}/h5/person-order-list?yhId="+localStorage.getItem("yhId");
}
});
}else{
alert("支付失败。");
window.location.href="${ctx}/h5/person-order-list?yhId="+localStorage.getItem("yhId");
}
}
});
});
}
</script>
</head>
<body οnlοad="pay()">
<input id="mergeId" type="hidden" value="${orderId}" />
<input id="appId" type="hidden" value="${appId}" />
<input id="timeStamp" type="hidden" value="${timeStamp}" />
<input id="nonceStr" type="hidden" value="${nonceStr}" />
<input id="package" type="hidden" value="${package}" />
<input id="signType" type="hidden" value="${signType}" />
<input id="paySign" type="hidden" value="${paySign}"/>
<input id="signature" type="hidden" value="${signature}"/>
</body>
</html>
完成支付,