微信公众号支付开发 + springmvc + jquery
最近在做一个带有微信公众号支付的项目,由于是新手,其中也遇到了不少问题,想着就写一篇博客,把遇到的问题记录下来,供他人参考,也留着以后回顾。
1:后台支付接口
@Controller
@RequestMapping("/payment")
public class PayController {
// 日志测试
Logger log = Logger.getLogger(PayController.class);
@Autowired AccessTokenService accessTokenService;
@RequestMapping(value = { "/wxPublicPay" })
@ResponseBody
public void wxPublicPay(HttpServletRequest request, HttpServletResponse response) {
Map<String, String> wxParam = new HashMap<String, String>();
Map<String, String> returnParam = new HashMap<String, String>();
// 首先获取用户的openId
String code = request.getParameter("code");
AccessToken accessToken = new AccessToken();
String openId = "";
accessToken = accessTokenService.getToken(code);
openId = accessToken.getOpenid(); // 获取用户openid
log.info("openid是:" + openId);
// 公众号id
wxParam.put("appid", WxConstants.APPID);
// 商户号
wxParam.put("mch_id", WxConstants.MCH_ID);
// 随机字符串
wxParam.put("nonce_str", genNonceStr());
// 商品描述
wxParam.put("body", "微信公众号支付测试");
// 订单号
wxParam.put("out_trade_no", getOrderID());
log.info("订单号out_trade_no是:" + wxParam.get("out_trade_no"));
// 支付金额 单位为分
wxParam.put("total_fee", "10"); // 0.1元
// 用户端ip
wxParam.put("spbill_create_ip", request.getRemoteAddr());
// 后台回调地址
wxParam.put("notify_url", "http://wechat/payment/wxPublicNotify");
// 交易类型
wxParam.put("trade_type", "JSAPI");
// openid trade_type=JSAPI时(即公众号支付),此参数必传
wxParam.put("openid", openId);
// 生成签名
String sign = PayUtils.createWeiSign(wxParam);
wxParam.put("sign", sign);
// 将map类型数据转换为xml格式
String entity = PayUtils.toXml(wxParam);
// 向微信发送请求
String content = PayUtils.sendPost("https://api.mch.weixin.qq.com/pay/unifiedorder", entity);
log.info("微信公众号支付返回的结果content为:" + content);
// 将微信返回的结果转换为XML格式
wxParam = PayUtils.readStringXmlOut(content);
if ("SUCCESS".equals(wxParam.get("return_code"))
&& "SUCCESS".equals(wxParam.get("result_code"))) { // 前端H5调起支付API
log.info("微信公众号支付请求成功!");
String paySign = "";
returnParam.put("appId", WxConstants.APPID); // 公众号id
returnParam.put("timeStamp", getTimeStamp()); // 时间戳
returnParam.put("nonceStr", genNonceStr()); // 随机字符串
// 统一下单接口返回的prepay_id参数值,提交格式如:prepay_id=***
returnParam.put("package", "prepay_id=" + wxParam.get("prepay_id"));
log.info("微信公众号支付时, package的值是:" + returnParam.get("package"));
returnParam.put("signType", "MD5");
paySign = PayUtils.createWeiSign(returnParam);
log.info("微信公众号支付时, 第二次签名paySign:" + paySign);
returnParam.put("paySign", paySign); // 签名
} else {
// 获取prepay_id(预支付交易会话标识)失败
log.info("微信公众号支付请求失败");
}
log.info("appId为:" + returnParam.get("appId").toString());
log.info("timeStamp为:" + returnParam.get("timeStamp").toString());
log.info("nonceStr为:" + returnParam.get("nonceStr").toString());
log.info("package为:" + returnParam.get("package").toString());
log.info("paySign为:" + returnParam.get("paySign").toString());
String resultJson = "{\"content\":{ " //content
+ "\"appId\": " + "\"" + returnParam.get("appId").toString() + "\"" + ","
+ "\"timeStamp\": " + "\"" + returnParam.get("timeStamp").toString() + "\"" + ","
+ "\"nonceStr\": " + "\"" + returnParam.get("nonceStr").toString() + "\"" + ","
+ "\"wx_package\": " + "\"" + returnParam.get("package").toString() + "\"" + ","
+ "\"paySign\": " + "\"" + returnParam.get("paySign").toString() + "\"" + "}" + "}";
log.info("返回给前端的resultJson信息是:" + resultJson);
try {
response.setContentType("text/json;charset=UTF-8");
response.getWriter().write(resultJson);
} catch (IOException e) {
e.printStackTrace();
}
}
2、前台页面
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="format-detection" content="telephone=no,adress=no" /> <title>微信公众号支付测试页面</title> <!-- 框架样式 --> <link rel="stylesheet" href="../resources/default/css/bootstrap.min.css"> <!-- 主题样式 --> <link rel="stylesheet" href="../resources/default/css/common.css"> <!-- 用户样式 --> <link rel="stylesheet" href="../resources/default/css/module-czx.css"> </head> <body> <h2>微信公众号支付测试页面-pages/index.jsp修改1</h2> <pre></pre> <button class="btn btn-default base-btn btn-exit" id="payBtn" style="width:94%;margin-left:3%;">点击支付</button> <script type="text/javascript" src="../resources/default/js/jquery.min.js"></script> <script type="text/javascript" src="../resources/default/js/jquery.tmpl.min.js"></script> <script type="text/javascript" src="../resources/default/js/common.js"></script> <script type="text/javascript"> var request = new UrlSearch(); // 实例化 var code = request.code; var appId; var timeStamp; var nonceStr; var wx_package; var signType; var paySign; $.ajax({ url : 'http://wechat/payment/wxPublicPay?code=' + code, type : 'post', dataType : 'json', contentType : 'application/json; charset=utf-8', async : false, success : function(data) { var data = data; appId = data.content.appId; timeStamp = data.content.timeStamp; nonceStr = data.content.nonceStr; wx_package = data.content.wx_package; paySign = data.content.paySign; } }); function onBridgeReady(){ alert("公众号支付测试页面---进入支付方法"); WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId" : appId, //公众号名称,由商户传入 "timeStamp": timeStamp, //时间戳,自1970年以来的秒数 "nonceStr" : nonceStr, //随机串 "package" : wx_package, "signType" : "MD5", //微信签名方式: "paySign" : paySign //微信签名 }, function (res) { alert(res.err_msg); // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 if((res.err_msg).indexOf("ok") >= 0) { alert("支付测试成功!"); } else { alert("支付失败!"); } } ); } // 立即支付按钮事件 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(); } } // 点击支付按钮事件 $("#payBtn").click(function(){ pay(); }); </script> </body> </html>