Java通过JsApi方式实现微信支付
要使用jsapi进行微信支付,首先要从微信获得一个prepay_id,然后通过调用微信的jsapi完成支付,js api的返回结果get_brand_wcpay_request:ok仅在用户成功完成支付时返回。由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。
示例代码如下:
function onbridgeready(){ weixinjsbridge.invoke( 'getbrandwcpayrequest', { "appid" : "wx2421b1c4370ec43b", //公众号名称,由商户传入 "timestamp":" 1395712654", //时间戳,自1970年以来的秒数 "noncestr" : "e61463f8efa94090b1f366cccfbbb444", //随机串 "package" : "u802345jgfjsdfgsdg888", "signtype" : "md5", //微信签名方式: "paysign" : "70ea570631e4bb79628fbca90534c63ff7fadd89" //微信签名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 } ); } 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(); }
以上传入的参数package,即为prepay_id
下面讲的是获得参数来调用jsapi
我们调用jsapi时,必须获得用户的openid,(trade_type=jsapi,openid为必填参数。)
首先定义一个请求的对象:
package com.unstoppedable.protocol; import com.unstoppedable.common.configure; import com.unstoppedable.common.httpservice; import com.unstoppedable.common.randomstringgenerator; import com.unstoppedable.common.signature; import java.lang.reflect.field; import java.util.hashmap; import java.util.map; public class unifiedorderreqdata { private string appid; private string mch_id; private string device_info; private string nonce_str; private string sign; private string body; private string detail; private string attach; private string out_trade_no; private string fee_type; private int total_fee; private string spbill_create_ip; private string time_start; private string time_expire; private string goods_tag; private string notify_url; private string trade_type; private string product_id; private string limit_pay; private string openid; private unifiedorderreqdata(unifiedorderreqdatabuilder builder) { this.appid = builder.appid; this.mch_id = builder.mch_id; this.device_info = builder.device_info; this.nonce_str = randomstringgenerator.getrandomstringbylength(32); this.body = builder.body; this.detail = builder.detail; this.attach = builder.attach; this.out_trade_no = builder.out_trade_no; this.fee_type = builder.fee_type; this.total_fee = builder.total_fee; this.spbill_create_ip = builder.spbill_create_ip; this.time_start = builder.time_start; this.time_expire = builder.time_expire; this.goods_tag = builder.goods_tag; this.notify_url = builder.notify_url; this.trade_type = builder.trade_type; this.product_id = builder.product_id; this.limit_pay = builder.limit_pay; this.openid = builder.openid; this.sign = signature.getsign(tomap()); } public void setappid(string appid) { this.appid = appid; } public void setmch_id(string mch_id) { this.mch_id = mch_id; } public void setdevice_info(string device_info) { this.device_info = device_info; } public void setnonce_str(string nonce_str) { this.nonce_str = nonce_str; } public void setsign(string sign) { this.sign = sign; } public void setbody(string body) { this.body = body; } public void setdetail(string detail) { this.detail = detail; } public void setattach(string attach) { this.attach = attach; } public void setout_trade_no(string out_trade_no) { this.out_trade_no = out_trade_no; } public void setfee_type(string fee_type) { this.fee_type = fee_type; } public void settotal_fee(int total_fee) { this.total_fee = total_fee; } public void setspbill_create_ip(string spbill_create_ip) { this.spbill_create_ip = spbill_create_ip; } public void settime_start(string time_start) { this.time_start = time_start; } public void settime_expire(string time_expire) { this.time_expire = time_expire; } public void setgoods_tag(string goods_tag) { this.goods_tag = goods_tag; } public void setnotify_url(string notify_url) { this.notify_url = notify_url; } public void settrade_type(string trade_type) { this.trade_type = trade_type; } public void setproduct_id(string product_id) { this.product_id = product_id; } public void setlimit_pay(string limit_pay) { this.limit_pay = limit_pay; } public void setopenid(string openid) { this.openid = openid; } public map<string, object> tomap() { map<string, object> map = new hashmap<string, object>(); field[] fields = this.getclass().getdeclaredfields(); for (field field : fields) { object obj; try { obj = field.get(this); if (obj != null) { map.put(field.getname(), obj); } } catch (illegalargumentexception e) { e.printstacktrace(); } catch (illegalaccessexception e) { e.printstacktrace(); } } return map; } public static class unifiedorderreqdatabuilder { private string appid; private string mch_id; private string device_info; private string body; private string detail; private string attach; private string out_trade_no; private string fee_type; private int total_fee; private string spbill_create_ip; private string time_start; private string time_expire; private string goods_tag; private string notify_url; private string trade_type; private string product_id; private string limit_pay; private string openid; public unifiedorderreqdatabuilder(string appid, string mch_id, string body, string out_trade_no, integer total_fee, string spbill_create_ip, string notify_url, string trade_type) { if (appid == null) { throw new illegalargumentexception("传入参数appid不能为null"); } if (mch_id == null) { throw new illegalargumentexception("传入参数mch_id不能为null"); } if (body == null) { throw new illegalargumentexception("传入参数body不能为null"); } if (out_trade_no == null) { throw new illegalargumentexception("传入参数out_trade_no不能为null"); } if (total_fee == null) { throw new illegalargumentexception("传入参数total_fee不能为null"); } if (spbill_create_ip == null) { throw new illegalargumentexception("传入参数spbill_create_ip不能为null"); } if (notify_url == null) { throw new illegalargumentexception("传入参数notify_url不能为null"); } if (trade_type == null) { throw new illegalargumentexception("传入参数trade_type不能为null"); } this.appid = appid; this.mch_id = mch_id; this.body = body; this.out_trade_no = out_trade_no; this.total_fee = total_fee; this.spbill_create_ip = spbill_create_ip; this.notify_url = notify_url; this.trade_type = trade_type; } public unifiedorderreqdatabuilder setdevice_info(string device_info) { this.device_info = device_info; return this; } public unifiedorderreqdatabuilder setdetail(string detail) { this.detail = detail; return this; } public unifiedorderreqdatabuilder setattach(string attach) { this.attach = attach; return this; } public unifiedorderreqdatabuilder setfee_type(string fee_type) { this.fee_type = fee_type; return this; } public unifiedorderreqdatabuilder settime_start(string time_start) { this.time_start = time_start; return this; } public unifiedorderreqdatabuilder settime_expire(string time_expire) { this.time_expire = time_expire; return this; } public unifiedorderreqdatabuilder setgoods_tag(string goods_tag) { this.goods_tag = goods_tag; return this; } public unifiedorderreqdatabuilder setproduct_id(string product_id) { this.product_id = product_id; return this; } public unifiedorderreqdatabuilder setlimit_pay(string limit_pay) { this.limit_pay = limit_pay; return this; } public unifiedorderreqdatabuilder setopenid(string openid) { this.openid = openid; return this; } public unifiedorderreqdata build() { if("jsapi".equals(this.trade_type) && this.openid == null) { throw new illegalargumentexception("当传入trade_type为jsapi时,openid为必填参数"); } if("native".equals(this.trade_type) && this.product_id == null) { throw new illegalargumentexception("当传入trade_type为native时,product_id为必填参数"); } return new unifiedorderreqdata(this); } } }
因为有些参数为必填,有些参数为选填。而且sign要等所有参数传入之后才能计算的出,所以这里用了builder模式。关于builder模式。
我们选用httpclient进行网络传输。
package com.unstoppedable.common; import com.thoughtworks.xstream.xstream; import com.thoughtworks.xstream.io.xml.domdriver; import com.thoughtworks.xstream.io.xml.xmlfriendlynamecoder; import org.apache.commons.logging.log; import org.apache.commons.logging.logfactory; import org.apache.http.httpentity; import org.apache.http.httpresponse; import org.apache.http.client.clientprotocolexception; import org.apache.http.client.responsehandler; import org.apache.http.client.config.requestconfig; import org.apache.http.client.methods.httpget; import org.apache.http.client.methods.httppost; import org.apache.http.conn.connecttimeoutexception; import org.apache.http.conn.connectionpooltimeoutexception; import org.apache.http.conn.ssl.sslconnectionsocketfactory; import org.apache.http.conn.ssl.sslcontexts; import org.apache.http.entity.stringentity; import org.apache.http.impl.client.closeablehttpclient; import org.apache.http.impl.client.httpclients; import org.apache.http.util.entityutils; import javax.net.ssl.sslcontext; import java.io.file; import java.io.fileinputstream; import java.io.ioexception; import java.net.sockettimeoutexception; import java.security.keystore; /** * created by hupeng on 2015/7/28. */ public class httpservice { private static log logger = logfactory.getlog(httpservice.class); private static closeablehttpclient httpclient = buildhttpclient(); //连接超时时间,默认10秒 private static int sockettimeout = 5000; //传输超时时间,默认30秒 private static int connecttimeout = 5000; private static int requesttimeout = 5000; public static closeablehttpclient buildhttpclient() { try { keystore keystore = keystore.getinstance("pkcs12"); fileinputstream instream = new fileinputstream(new file(configure.getcertlocalpath()));//加载本地的证书进行https加密传输 try { keystore.load(instream, configure.getcertpassword().tochararray());//设置证书密码 } finally { instream.close(); } // trust own ca and all self-signed certs sslcontext sslcontext = sslcontexts.custom() .loadkeymaterial(keystore, configure.getcertpassword().tochararray()) .build(); // allow tlsv1 protocol only sslconnectionsocketfactory sslsf = new sslconnectionsocketfactory( sslcontext, new string[]{"tlsv1"}, null, sslconnectionsocketfactory.browser_compatible_hostname_verifier); requestconfig requestconfig = requestconfig.custom() .setconnecttimeout(connecttimeout) .setconnectionrequesttimeout(requesttimeout) .setsockettimeout(sockettimeout).build(); httpclient = httpclients.custom() .setdefaultrequestconfig(requestconfig) .setsslsocketfactory(sslsf) .build(); return httpclient; } catch (exception e) { throw new runtimeexception("error create httpclient......", e); } } public static string doget(string requesturl) throws exception { httpget httpget = new httpget(requesturl); try { logger.debug("executing request " + httpget.getrequestline()); // create a custom response handler responsehandler<string> responsehandler = new responsehandler<string>() { @override public string handleresponse( final httpresponse response) throws clientprotocolexception, ioexception { int status = response.getstatusline().getstatuscode(); if (status >= 200 && status < 300) { httpentity entity = response.getentity(); return entity != null ? entityutils.tostring(entity) : null; } else { throw new clientprotocolexception("unexpected response status: " + status); } } }; return httpclient.execute(httpget, responsehandler); } finally { httpget.releaseconnection(); } } public static string dopost(string url, object object2xml) { string result = null; httppost httppost = new httppost(url); //解决xstream对出现双下划线的bug xstream xstreamforrequestpostdata = new xstream(new domdriver("utf-8", new xmlfriendlynamecoder("-_", "_"))); //将要提交给api的数据对象转换成xml格式数据post给api string postdataxml = xstreamforrequestpostdata.toxml(object2xml); logger.info("api,post过去的数据是:"); logger.info(postdataxml); //得指明使用utf-8编码,否则到api服务器xml的中文不能被成功识别 stringentity postentity = new stringentity(postdataxml, "utf-8"); httppost.addheader("content-type", "text/xml"); httppost.setentity(postentity); //设置请求器的配置 logger.info("executing request" + httppost.getrequestline()); try { httpresponse response = httpclient.execute(httppost); httpentity entity = response.getentity(); result = entityutils.tostring(entity, "utf-8"); } catch (connectionpooltimeoutexception e) { logger.error("http get throw connectionpooltimeoutexception(wait time out)", e); } catch (connecttimeoutexception e) { logger.error("http get throw connecttimeoutexception", e); } catch (sockettimeoutexception e) { logger.error("http get throw sockettimeoutexception", e); } catch (exception e) { logger.error("http get throw exception", e); } finally { httppost.abort(); } return result; } }
然后是我们的总入口:
package com.unstoppedable.service; import com.unstoppedable.common.configure; import com.unstoppedable.common.httpservice; import com.unstoppedable.common.xmlparser; import com.unstoppedable.protocol.unifiedorderreqdata; import org.xml.sax.saxexception; import javax.xml.parsers.parserconfigurationexception; import java.io.ioexception; import java.util.map; /** * created by hupeng on 2015/7/28. */ public class wxpayapi { public static map<string,object> unifiedorder(unifiedorderreqdata reqdata) throws ioexception, saxexception, parserconfigurationexception { string res = httpservice.dopost(configure.unified_order_api, reqdata); return xmlparser.getmapfromxml(res); } public static void main(string[] args) throws exception { unifiedorderreqdata reqdata = new unifiedorderreqdata.unifiedorderreqdatabuilder("appid", "mch_id", "body", "out_trade_no", 1, "spbill_create_ip", "notify_url", "jsapi").setopenid("openid").build(); system.out.println(unifiedorder(reqdata)); } }
返回的xml为:
<xml> <return_code><![cdata[success]]></return_code> <return_msg><![cdata[ok]]></return_msg> <appid><![cdata[wx2421b1c4370ec43b]]></appid> <mch_id><![cdata[10000100]]></mch_id> <nonce_str><![cdata[iitri8iabbblz1jc]]></nonce_str> <sign><![cdata[7921e432f65eb8ed0ce9755f0e86d72f]]></sign> <result_code><![cdata[success]]></result_code> <prepay_id><![cdata[wx201411101639507cbf6ffd8b0779950874]]></prepay_id> <trade_type><![cdata[jsapi]]></trade_type> </xml>
return_code 和result_code都为success的时候会返回我们需要的prepay_id。。。,然后在jsapi中使用他就可以了。。
本文已被整理到了《javascript微信开发技巧汇总》,《android微信开发教程汇总》,《java微信开发教程汇总》欢迎大家学习阅读。
为大家推荐现在关注度比较高的微信小程序教程一篇:《微信小程序开发教程》小编为大家精心整理的,希望喜欢。
以上就是本文的全部内容,希望对大家的学习有所帮助。
上一篇: Android播放视频的三种方式
下一篇: C# 递归函数详细介绍及使用方法