后台代码::
@At("/pay/?")
@Ok("beetl:/public/wx/test/pay.html")
public void pay(String id, @Param("money") int money, HttpServletRequest req, HttpSession session) {
String openid = Strings.sNull(session.getAttribute("openid"));
String wxid = Strings.sNull(session.getAttribute("wxid"));
log.debug("pay money:::" + money);
log.debug("pay wxid:::" + wxid);
log.debug("pay openid:::" + openid);
Wx_config config = wxConfigService.fetch(wxid);
NutMap payinfo = Json.fromJson(NutMap.class, config.getPayInfo());
WxApi2 wxApi2 = wxConfigService.getWxApi2(wxid);
if (Lang.isEmpty(Globals.memoryJsapiTicketStore.get(wxid))) {
Globals.memoryJsapiTicketStore.put(wxid, new MemoryJsapiTicketStore());
}
MemoryJsapiTicketStore memoryJsapiTicketStore = Globals.memoryJsapiTicketStore.get(wxid);
wxApi2.setJsapiTicketStore(memoryJsapiTicketStore);
String url = "http://" + Globals.AppDomain + Globals.AppBase + "/test/pay/" + Strings.sNull(access_number);
NutMap jsConfig = wxApi2.genJsSDKConfig(url, "chooseWXPay");
String nonce_str=R.UU32();
WxPayUnifiedOrder order = new WxPayUnifiedOrder();
order.setAppid(config.getAppid());
order.setMch_id(payinfo.getString("wxpay_mchid"));
order.setNonce_str(nonce_str);
order.setBody("Test");//运行环境 -Dfile.encoding=UTF-8
order.setOut_trade_no(DateUtil.format(new Date(), "yyyyMMddHHmmss"));
order.setTotal_fee(money);
order.setSpbill_create_ip(Globals.AppIp);
order.setNotify_url("http://" + Globals.AppDomain + Globals.AppBase + "/test/payback");
order.setTrade_type("JSAPI");
order.setOpenid(openid);//JSAPI时openid必填
order.setProduct_id("Test");
order.setAttach("购买套餐");
log.debug("order:::" + Json.toJson(order));
NutMap resp = wxApi2.pay_jsapi(payinfo.getString("wxpay_key"), order);
String return_code = resp.getString("return_code", "");//SUCCESS
log.debug("return_code:::" + return_code);
log.debug("resp:::" + Json.toJson(resp));
req.setAttribute("jsConfig", Json.toJson(jsConfig));
req.setAttribute("money", money);
req.setAttribute("moneys", MoneyUtil.fenToYuan(money));
req.setAttribute("resp", resp);
req.setAttribute("id", id);
}
//支付成功回调处理
@At("/payback")
@Ok("raw")
@AdaptBy(type = VoidAdaptor.class)
public String payback(Reader reader) throws IOException {
NutMap res = Xmls.xmlToMap(Streams.readAndClose(reader));
log.debug("res::" + Json.toJson(res));
Map<String, Object> map = new HashMap<>();
map.put("return_code", "SUCCESS");
return Xmls.mapToXml(map);
}
前台页面:
<script language="JavaScript">
wx.config(${jsConfig});
function wxPay() {
WeixinJSBridge.invoke('getBrandWCPayRequest', {
appId:'${resp.appId!}',
timeStamp: '${resp.timeStamp!}',
nonceStr: '${resp.nonceStr!}',
package: '${resp.package!}',
signType: '${resp.signType!}',
paySign: '${resp.paySign!}'
},function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
//微信团队郑重提示:res.err_msg 将在用户支付成功后返回 ok,但并不保证它绝对可靠。
window.location.href="${base!}/test/success/${id}";
}
if (res.err_msg == "get_brand_wcpay_request:fail") {
window.location.href="${base!}/test/fail/${id}";
}
});
}
wx.ready(function(){
wxPay();
});
</script>
注意事项:
1、微信公众号后台,需设置支付授权目录 ;
2、微信公众号后台,需添加access_token IP白名单(业务需要,通过code获取openid等);
3、注意金额单位是分;
4、JS返回的成功,不确定一定是成功的,所以业务需要在回调里再次处理;