微信支付文档上有刷卡支付,扫码支付,公众号支付,APP支付等各种支付手段。本次就微信内打开的网页支付为例子,用java进行实现一下。微信内网页支付可以将其归属为公众号支付。
一、设置支付目录
打开微信商户平台,设置路径:商户平台-->产品中心-->开发配置,如图7.7所示。公众号支付在请求支付的时候会校验请求来源是否有在商户平台做了配置,所以必须确保支付目录已经正确的被配置,否则将验证失败,请求支付不成功。
二、设置授权域名
开发公众号支付时,在统一下单接口中要求必传用户openid,而获取openid则需要您在公众平台设置获取openid的域名,只有被设置过的域名才是一个有效的获取openid的域名,否则将获取失败。
完成以上两步后,微信端的支付端口就能够被我们的网站调用了。
三、分析业务时序图
微信在官方文档中用时序图反映了其对应的业务流程。
根据此图,可以看出流程大致为:自己的java后台生成付款链接,用户点击链接,在java后台中生成商户订单,将此订单按照微信的格式发送给微信支付系统,微信支付系统生成一个预付单给java后台,然后在java后台中生成支付参数返回给用户,用户点击付款,会向微信支付系统检查支付参数的合法性,确认无误后即可完成付款操作。付款完成后异步通知商户付款结果,并会跳到指定的付款成功页面。
四、java实现
1、首先需要调用微信支付的包,加入到pom.xml中。
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
2、在页面中,需要点击支付按钮发生的事件如下,首先跳转到自己的后台,返回支付所需要的支付参数,并存进js的元素中,留给pay2()使用。其中'${redirect_uri}'这个值是自己之前填进去的域名。只不过这里我为了方便管理,讲其写入了配置文件,可以让其作为后台返回的一个值传进js中。
function pay(){
var redirect_uri = 'http://'+'${redirect_uri}'+"/xjwUtil/mobile/user/pay/";
jQuery.ajax({
url : redirect_uri,
datatype : 'json',
type : "Post",
scriptCharset: 'utf-8',
contentType: "application/x-www-form-urlencoded; charset=utf-8",
success : function(data) {
var d = eval('('+data +')');
jQuery('#appId').val();
jQuery('#timeStamp').val(d.timeStamp);
jQuery('#nonceStr').val(d.nonceStr);
jQuery('#signType').val(d.signType);
jQuery('#paySign').val(d.paySign);
jQuery('#package').val(d.pk);
pay2();
}
})
}
3、通过"mobile/user/pay/"这个地址对应的java处理Controller如下代码所示,目的是返回支付所需要的参数值。其中openId这一参数是在用户使用微信登录时被我存入session中的。重点在于WXPayExample.yy(openId)这里,这个类是通过openId获取预付款信息的通道。
Controller.java
@RequestMapping(value = "/pay/", method = RequestMethod.POST)
@ResponseBody
public String pay(HttpServletRequest req, HttpServletResponse resp){
Map<String,String> m= new HashMap<String,String>();
try {
req.setCharacterEncoding("utf-8");
String openId=(String)req.getSession().getAttribute("openId");
Map<String,String> result=WXPayExample.yy(openId);
String nonceStr=result.get("nonce_str");
String package1="prepay_id="+result.get("prepay_id");
m.put("appId","************");
m.put("package", package1);
m.put("nonceStr", nonceStr);
long time=System.currentTimeMillis()/1000;
m.put("timeStamp",time+"");
m.put("signType", "MD5");
m.put("paySign", WXPayUtil.generateSignature(m,"*********************", SignType.MD5));
String reqBody =WXPayUtil.mapToXml(m);
m.put("pk", package1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String result1 = JSON.toJSONString(m);
return result1;
}
在WXPayExample类中,第一步还是通过MyConfig()配置获取服务号APPID,商户号,和Key,并且加载支付证书。然后填写支付信息中的随机码,支付金额,付款方式,付款URL等。然后由WXPay将其添加签名,WxPayUtil将其转化为xml文件,通过wxpay.unifiedOrder(data)发送给微信支付平台,并获取返回值。其中这个三个包都可以需要导入
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants.SignType;
import com.github.wxpay.sdk.WXPayUtil;
WXPayExample.java
public static Map<String,String> yy(String openId) throws Exception {
MyConfig config = new MyConfig();
WXPay wxpay = new WXPay(config);
Map<String, String> data = new HashMap<String, String>();
data.put("body", "xx");
data.put("out_trade_no", WXPayUtil.generateNonceStr());
data.put("device_info", "");
data.put("fee_type", "CNY");
data.put("total_fee", "1");
data.put("spbill_create_ip", "192.168.31.166");
data.put("openid",openId);
data.put("notify_url", "http://"+GetPeizhi.serverName+"/xjwUtil");
data.put("trade_type", "JSAPI");
try {
Map<String, String> data2 = wxpay.fillRequestData(data);
String reqBody =WXPayUtil.mapToXml(data2);
System.out.println(reqBody);
Map<String, String> resp = wxpay.unifiedOrder(data);
System.out.println(resp);
return resp;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
MyConfig.java
import com.github.wxpay.sdk.WXPayConfig;
import java.io.*;
public class MyConfig implements WXPayConfig{
private byte[] certData;
public MyConfig() throws Exception {
String certPath=this.getClass().getResource("/*****证书******").getPath();
File file = new File(certPath);
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();
}
public String getAppID() {
return "***********";
}
public String getMchID() {
return "***********";
}
public String getKey() {
return "***********";
}
public InputStream getCertStream() {
ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
return certBis;
}
public int getHttpConnectTimeoutMs() {
return 8000;
}
public int getHttpReadTimeoutMs() {
return 10000;
}
}
4,这个时候,就已经可以拿到预付款信息了。里面有一个预付款prepay_id就是微信平台中的该条预付款信息的ID。将返回的nonceStr,prepay_id按照要求封装为package与其他的参数打包在一起。并添加一个签名。然后把签名和其他所有的标签放进map集合后,转成result1发送给页面。用户既可以选择支付了。
5、用户支付的javascript。回到cart.jsp中,第二步中的ajax获取到返回值之后,就可以进行下一步操作了。pay2()这一个function是用户支付指令的发送,当微信支付准备好了之后,通过onBridgeReady()这一方法进行付款,如果付款成功,调用success方法,失败后直接跳转到失败页面。至此,这个整个过程就宣告结束。
cart.jsp
function pay2() {
var appId = jQuery('#appId').val();
var timeStamp = jQuery('#timeStamp').val();
var nonceStr = jQuery('#nonceStr').val();
var signType = jQuery('#signType').val();
var pk = jQuery('#package').val();
var paySign = jQuery('#paySign').val();
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();
}
function onBridgeReady() {
console.log(appId + "==" + timeStamp + "==" + nonceStr + "==" + pk
+ "==" + "MD5" + "==" + paySign + "")
WeixinJSBridge.invoke('getBrandWCPayRequest', {
"appId" : appId, //公众号名称,由商户传入
"timeStamp" : timeStamp, //时间戳,自1970年以来的秒数
"nonceStr" : nonceStr, //随机串
"package" : pk,
"signType" : "MD5", //微信签名方式:
"paySign" : paySign
//微信签名
}, function(res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
success();
} // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
else{
window.location.href="${pageContext.request.contextPath}/mobile/user/payfail/"
}
});
}
}
function success(){
jQuery.ajax({
url : "${pageContext.request.contextPath}/mobile/user/paysuccess/",
datatype : 'json',
type : "Post",
scriptCharset: 'utf-8',
contentType: "application/x-www-form-urlencoded; charset=utf-8",
success : function(data) {
window.location.href="${pageContext.request.contextPath}/mobile/user/success2"
}
})
}
五、另附
使用微信支付时需要用到appId这一变量。在上文中appId通过session取出,初次使用appID 的获取方法如下:
还是在下一篇博客写吧。。。