您好,欢迎访问一九零五行业门户网

Java实现JsApi方式的微信支付

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详细文档见:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7
下面讲的是获得参数来调用jsapi我们调用jsapi时,必须获得用户的openid,(trade_type=jsapi,openid为必填参数。)首先定义一个请求的对象:
package com.unstoppedable.protocol;import com.thoughtworks.xstream.annotations.xstreamalias;import com.unstoppedable.common.configure;import com. unstoppedable.common.randomstringgenerator;import com.unstoppedable.common.signature;import java.lang.reflect.field;import java.util.hashmap; import java.util.map;@xstreamalias("xml") 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 string getappid() { return appid; } public string getmch_id() { return mch_id; } public string getdevice_info() { return device_info; } public string getnonce_str() { return nonce_str; } public string getsign() { return sign; } public string getbody() { return body; } public string getdetail() { return detail; } public string getattach() { return attach; } public string getout_trade_no() { return out_trade_no; } public string getfee_type() { return fee_type; } public int gettotal_fee() { return total_fee; } public string getspbill_create_ip() { return spbill_create_ip; } public string gettime_start() { return time_start; } public string gettime_expire() { return time_expire; } public string getgoods_tag() { return goods_tag; } public string getnotify_url() { return notify_url; } public string gettrade_type() { return trade_type; } public string getproduct_id() { return product_id; } public string getlimit_pay() { return limit_pay; } public string getopenid() { return 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; /** * 使用配置中的 appid 和 mch_id * * @param body * @param out_trade_no * @param total_fee * @param spbill_create_ip * @param notify_url * @param trade_type */ public unifiedorderreqdatabuilder(string body, string out_trade_no, integer total_fee, string spbill_create_ip, string notify_url, string trade_type) { this(configure.getappid(), configure.getmchid(), body, out_trade_no, total_fee, spbill_create_ip, notify_url, trade_type); } 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模式。关于每个参数的定义,参考说明文档https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
我们选用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中使用他就可以了。。
以上就是java实现jsapi方式的微信支付的内容。
其它类似信息

推荐信息