微信支付jsapi
商户已有H5商城网站,用户通过消息或扫描二维码在微信内打开网页时,可以调用微信支付完成下单购买的流程。
jspi支付,是指微信公众号里面的打开网站,支付
大致流程
- 获取所需参数
- 发送给统一下单的接口
- 根据返回的参数,进行解析,如果成功,将部分参数发送给前台。注意前台的浏览器是微信内置浏览器,有一个内置的js对象,可以通过js对象,调起支付
- 最后跳转到结果页面
正式开发
jsapi统一下单api列表
下面列举必须字段
Appid,mch_id,nonce_str,sign,body,out_trade_no,total_fee,spbill_create_ip,notify_url,trade_type,openid
注意:total_fee是分为单位
String total_fee = info.getOrderMoney().multiply(new BigDecimal("100")).intValue()+"";
说下不好获取的
spbill_create_ip:我当时就是写了127.0.0.1,我并不清楚怎么获取
notify_url:写公网可以访问的地址,最好去看下官网的介绍,
out_trade_no:前6位是随机数,后面是数据库中实际的订单编号,这样是为了回调的时候获取订单编号,当然也可以使用别的方法。
openid:是指一个用户到一个公众号,对应的一个key,是唯一的,获取方法文档
我的思路是,先获取code,H5界面里面,有一个去支付按钮,而去支付按钮是一个超链接
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx1111111111111111&redirect_uri=http%3A%2F%2Fm.XXXX.com%2FpayList.html%3ForderNumber%3D"+orderNum+"&response_type=code&scope=snsapi_base&state=123#wechat_redirect";
这里面的redirect_uri需要格式化
import java.net.URLEncoder;
String formatUrl = URLEncoder.encode("http://m.XXXX.com/payList.html?orderNumber=XXXXXXX","UTF_8");
跳转回来的时候是
http://m.XXXX.com/payList.html?orderNumber=XXXXXXX&code=sdhjsdhfjhasjhfhjasdhbavbnb
这个code呢,你开发在电脑端是看不见的,这也就是微信坑的地方,所以你 下载微信开发者工具
获取code之后,点击微信支付,发送ajax请求给后台
@RequestMapping("/payH5")
@ResponseBody
public Object payH5(@RequestParam("orderNumber") String orderNumber, @RequestParam("type") Integer type, HttpServletRequest request, HttpServletResponse response,@RequestParam(value = "code",defaultValue = "")String code) throws Exception{
try{
OrderInfo info = orderInfoService.selectOne(new EntityWrapper<OrderInfo>()
.eq("order_number", orderNumber));
ModelAndView modelAndView = new ModelAndView();
//支付宝支付
if(type.intValue()==1){
response.sendRedirect("http://m.XXXX.com/alipay.html?orderNumber="+orderNumber);
//微信支付
}else if(type.intValue()==0){
if("".equals(code)){
return "返回错误界面";
}
WxpayConfig wxpayConfig = new WxpayConfig();
//此处获取openid,后台发请求给,通过code,appId,appsecret
String res = HttpUtil.sendGet("https://api.weixin.qq.com/sns/oauth2/access_token",
"appid="+wxpayConfig.getApp_id()+"&secret="+wxpayConfig.getApp_secret()+"&code="+code+"&grant_type=authorization_code");
JSONObject json = JSONObject.parseObject(res);
String openId = json.getString("openid");
Map<String,String> paraMap = new HashMap<>();
paraMap.put("appid",wxpayConfig.getApp_id());
paraMap.put("body",info.getOrderProject());
paraMap.put("mch_id",wxpayConfig.getMch_id());
paraMap.put("nonce_str", WXPayUtil.generateNonceStr());
paraMap.put("openid",openId);
String randomNum = (int)((Math.random()*9+1)*100000)+"";
String orderNo =randomNum+orderNumber;
paraMap.put("out_trade_no",orderNo);
paraMap.put("spbill_create_ip",wxpayConfig.getSpbill_create_ip());
String total_fee = info.getOrderMoney().multiply(new BigDecimal("100")).intValue()+"";
paraMap.put("total_fee",total_fee);
paraMap.put("trade_type",wxpayConfig.getTrade_type());
paraMap.put("notify_url","http://XXXX.com/XXXX/api/wxnotify?orderNumber="+orderNumber);
String apiKey = wxpayConfig.getApi_key();
String sign = WXPayUtil.generateSignature(paraMap,apiKey);
paraMap.put("sign",sign);
String xml = WXPayUtil.mapToXml(paraMap);
//统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
String xmlStr = HttpUtil.sendPost(unifiedorder_url,xml,false);
//以下内容是返回前端页面的json数据
String prepay_id = "";//预支付id
if (xmlStr.indexOf("SUCCESS") != -1) {
Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
prepay_id = (String) map.get("prepay_id");
}
Map<String, String> payMap = new HashMap<String, String>();
payMap.put("appId", wxpayConfig.getApp_id());
payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp()+"");
payMap.put("nonceStr", WXPayUtil.generateNonceStr());
payMap.put("signType", "MD5");
payMap.put("package", "prepay_id=" + prepay_id);
String paySign = WXPayUtil.generateSignature(payMap, wxpayConfig.getApi_key());
payMap.put("paySign", paySign);
return payMap;
}
return "";
}catch (Exception e){
e.printStackTrace();
}
return "end";
// return new SuccessResponseData();
}
获取sign
下载后,里面有一些工具类,WXPayUtil里面有一个方法可以获取
返回数据到前台后,前台调用js对象,执行
WeixinJSBridge.invoke( 'getBrandWCPayRequest', {
"appId":appId, //公众号名称,由商户传入
"timeStamp":timeStamp, //时间戳,自1970年以来的秒数
"nonceStr":nonceStr, //随机串
"package":package,
"signType":signType, //微信签名方式:
"paySign":paySign //微信签名
}, function(res){
console.log(res);
window.location.href = "http://m.XXXX.com/orderDetail.html?orderNum="+orderNumber;
// if(res.err_msg == "get_brand_wcpay_request:ok" ) {
// console.log('支付成功');
// //支付成功后跳转的页面
// }else if(res.err_msg == "get_brand_wcpay_request:cancel"){
// console.log('支付取消');
// }else if(res.err_msg == "get_brand_wcpay_request:fail"){
// console.log('支付失败');
// } //使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
}
就会执行微信支付,不管成功没有,都会跳转到orderDetail界面,查看order详情
微信回调
微信会返回结果
我应该处理什么
- 告诉微信,我收到了,返回success
- 对订单信息,获取orderNum,对订单状态进行更新
@RequestMapping("/wxnotify")
public String wxnotify(HttpServletRequest request,HttpServletResponse response){
InputStream is = null;
try{
is = request.getInputStream();
String xml = WXPayUtil.inputStream2String(is);
Map<String,String> notifyMap = WXPayUtil.xmlToMap(xml);
if(notifyMap.get("return_code").equals("SUCCESS")) {
String orderNumber = notifyMap.get("out_trade_no").substring(6);
OrderInfo info = orderInfoService.selectOne(new EntityWrapper<OrderInfo>()
.eq("order_number", orderNumber));
info.setOrderState(1);
orderInfoService.updateById(info);
String amount = notifyMap.get("total_fee");
System.out.println("实际付款:"+amount);
}
response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
is.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}