站内搜索

详解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

下面讲的是获得参数来调用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中使用他就可以了。。

以上就是详解Java通过JsApi方式实现微信支付方法的详细内容,更多请关注php中文网其它相关文章!

  • 上一篇:Android 高仿微信支付数字键盘功能
  • 下一篇:使用c#开发公众平台自定义菜单功能实例代码