UDN-企业互联网技术人气社区

板块导航

浏览  : 513
回复  : 2

[原生js] Java通过JsApi方式实现微信支付

[复制链接]
西北的风的头像 楼主
发表于 2017-1-17 14:17:28 | 显示全部楼层 |阅读模式
  本文讲解了Java如何实现JsAPI方式的微信支付,代码内容详细,文章思路清晰,需要的朋友可以参考下

  要使用JsApi进行微信支付,首先要从微信获得一个prepay_id,然后通过调用微信的jsapi完成支付,JS API的返回结果get_brand_wcpay_request:ok仅在用户成功完成支付时返回。由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。
  
  示例代码如下:
  1. function onBridgeReady(){
  2. WeixinJSBridge.invoke(
  3. 'getBrandWCPayRequest', {
  4.   "appId" : "wx2421b1c4370ec43b", //公众号名称,由商户传入
  5.   "timeStamp":" 1395712654",  //时间戳,自1970年以来的秒数
  6.   "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //随机串
  7.   "package" : "u802345jgfjsdfgsdg888",
  8.   "signType" : "MD5",  //微信签名方式:
  9.   "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名
  10. },
  11. function(res){
  12.   if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
  13. }
  14. );
  15. }
  16. if (typeof WeixinJSBridge == "undefined"){
  17. if( document.addEventListener ){
  18. document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
  19. }else if (document.attachEvent){
  20. document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
  21. document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
  22. }
  23. }else{
  24. onBridgeReady();
  25. }
复制代码

  以上传入的参数package,即为prepay_id
  
  下面讲的是获得参数来调用jsapi
  
  我们调用JSAPI时,必须获得用户的openid,(trade_type=JSAPI,openid为必填参数。)
  
  首先定义一个请求的对象:
  1. package com.unstoppedable.protocol;



  2. import com.unstoppedable.common.Configure;
  3. import com.unstoppedable.common.HttpService;
  4. import com.unstoppedable.common.RandomStringGenerator;
  5. import com.unstoppedable.common.Signature;

  6. import java.lang.reflect.Field;
  7. import java.util.HashMap;
  8. import java.util.Map;


  9. public class UnifiedOrderReqData {

  10. private String appid;
  11. private String mch_id;
  12. private String device_info;
  13. private String nonce_str;
  14. private String sign;
  15. private String body;
  16. private String detail;
  17. private String attach;
  18. private String out_trade_no;
  19. private String fee_type;
  20. private int total_fee;
  21. private String spbill_create_ip;
  22. private String time_start;
  23. private String time_expire;
  24. private String goods_tag;
  25. private String notify_url;
  26. private String trade_type;
  27. private String product_id;
  28. private String limit_pay;
  29. private String openid;

  30. private UnifiedOrderReqData(UnifiedOrderReqDataBuilder builder) {
  31. this.appid = builder.appid;
  32. this.mch_id = builder.mch_id;
  33. this.device_info = builder.device_info;
  34. this.nonce_str = RandomStringGenerator.getRandomStringByLength(32);
  35. this.body = builder.body;
  36. this.detail = builder.detail;
  37. this.attach = builder.attach;
  38. this.out_trade_no = builder.out_trade_no;
  39. this.fee_type = builder.fee_type;
  40. this.total_fee = builder.total_fee;
  41. this.spbill_create_ip = builder.spbill_create_ip;
  42. this.time_start = builder.time_start;
  43. this.time_expire = builder.time_expire;
  44. this.goods_tag = builder.goods_tag;
  45. this.notify_url = builder.notify_url;
  46. this.trade_type = builder.trade_type;
  47. this.product_id = builder.product_id;
  48. this.limit_pay = builder.limit_pay;
  49. this.openid = builder.openid;
  50. this.sign = Signature.getSign(toMap());
  51. }


  52. public void setAppid(String appid) {
  53. this.appid = appid;
  54. }

  55. public void setMch_id(String mch_id) {
  56. this.mch_id = mch_id;
  57. }

  58. public void setDevice_info(String device_info) {
  59. this.device_info = device_info;
  60. }

  61. public void setNonce_str(String nonce_str) {
  62. this.nonce_str = nonce_str;
  63. }

  64. public void setSign(String sign) {
  65. this.sign = sign;
  66. }

  67. public void setBody(String body) {
  68. this.body = body;
  69. }

  70. public void setDetail(String detail) {
  71. this.detail = detail;
  72. }

  73. public void setAttach(String attach) {
  74. this.attach = attach;
  75. }

  76. public void setOut_trade_no(String out_trade_no) {
  77. this.out_trade_no = out_trade_no;
  78. }

  79. public void setFee_type(String fee_type) {
  80. this.fee_type = fee_type;
  81. }

  82. public void setTotal_fee(int total_fee) {
  83. this.total_fee = total_fee;
  84. }

  85. public void setSpbill_create_ip(String spbill_create_ip) {
  86. this.spbill_create_ip = spbill_create_ip;
  87. }

  88. public void setTime_start(String time_start) {
  89. this.time_start = time_start;
  90. }

  91. public void setTime_expire(String time_expire) {
  92. this.time_expire = time_expire;
  93. }

  94. public void setGoods_tag(String goods_tag) {
  95. this.goods_tag = goods_tag;
  96. }

  97. public void setNotify_url(String notify_url) {
  98. this.notify_url = notify_url;
  99. }

  100. public void setTrade_type(String trade_type) {
  101. this.trade_type = trade_type;
  102. }

  103. public void setProduct_id(String product_id) {
  104. this.product_id = product_id;
  105. }

  106. public void setLimit_pay(String limit_pay) {
  107. this.limit_pay = limit_pay;
  108. }

  109. public void setOpenid(String openid) {
  110. this.openid = openid;
  111. }

  112. public Map<String, Object> toMap() {
  113. Map<String, Object> map = new HashMap<String, Object>();
  114. Field[] fields = this.getClass().getDeclaredFields();
  115. for (Field field : fields) {
  116.   Object obj;
  117.   try {
  118.   obj = field.get(this);
  119.   if (obj != null) {
  120.    map.put(field.getName(), obj);
  121.   }
  122.   } catch (IllegalArgumentException e) {
  123.   e.printStackTrace();
  124.   } catch (IllegalAccessException e) {
  125.   e.printStackTrace();
  126.   }
  127. }
  128. return map;
  129. }


  130. public static class UnifiedOrderReqDataBuilder {
  131. private String appid;
  132. private String mch_id;
  133. private String device_info;
  134. private String body;
  135. private String detail;
  136. private String attach;
  137. private String out_trade_no;
  138. private String fee_type;
  139. private int total_fee;
  140. private String spbill_create_ip;
  141. private String time_start;
  142. private String time_expire;
  143. private String goods_tag;
  144. private String notify_url;
  145. private String trade_type;
  146. private String product_id;
  147. private String limit_pay;
  148. private String openid;

  149. public UnifiedOrderReqDataBuilder(String appid, String mch_id, String body, String out_trade_no, Integer total_fee,
  150.       String spbill_create_ip, String notify_url, String trade_type) {
  151.   if (appid == null) {
  152.   throw new IllegalArgumentException("传入参数appid不能为null");
  153.   }
  154.   if (mch_id == null) {
  155.   throw new IllegalArgumentException("传入参数mch_id不能为null");
  156.   }
  157.   if (body == null) {
  158.   throw new IllegalArgumentException("传入参数body不能为null");
  159.   }
  160.   if (out_trade_no == null) {
  161.   throw new IllegalArgumentException("传入参数out_trade_no不能为null");
  162.   }
  163.   if (total_fee == null) {
  164.   throw new IllegalArgumentException("传入参数total_fee不能为null");
  165.   }
  166.   if (spbill_create_ip == null) {
  167.   throw new IllegalArgumentException("传入参数spbill_create_ip不能为null");
  168.   }
  169.   if (notify_url == null) {
  170.   throw new IllegalArgumentException("传入参数notify_url不能为null");
  171.   }
  172.   if (trade_type == null) {
  173.   throw new IllegalArgumentException("传入参数trade_type不能为null");
  174.   }
  175.   this.appid = appid;
  176.   this.mch_id = mch_id;
  177.   this.body = body;
  178.   this.out_trade_no = out_trade_no;
  179.   this.total_fee = total_fee;
  180.   this.spbill_create_ip = spbill_create_ip;
  181.   this.notify_url = notify_url;
  182.   this.trade_type = trade_type;
  183. }

  184. public UnifiedOrderReqDataBuilder setDevice_info(String device_info) {
  185.   this.device_info = device_info;
  186.   return this;
  187. }

  188. public UnifiedOrderReqDataBuilder setDetail(String detail) {
  189.   this.detail = detail;
  190.   return this;
  191. }

  192. public UnifiedOrderReqDataBuilder setAttach(String attach) {
  193.   this.attach = attach;
  194.   return this;
  195. }

  196. public UnifiedOrderReqDataBuilder setFee_type(String fee_type) {
  197.   this.fee_type = fee_type;
  198.   return this;
  199. }

  200. public UnifiedOrderReqDataBuilder setTime_start(String time_start) {
  201.   this.time_start = time_start;
  202.   return this;
  203. }

  204. public UnifiedOrderReqDataBuilder setTime_expire(String time_expire) {
  205.   this.time_expire = time_expire;
  206.   return this;
  207. }

  208. public UnifiedOrderReqDataBuilder setGoods_tag(String goods_tag) {
  209.   this.goods_tag = goods_tag;
  210.   return this;
  211. }

  212. public UnifiedOrderReqDataBuilder setProduct_id(String product_id) {
  213.   this.product_id = product_id;
  214.   return this;
  215. }

  216. public UnifiedOrderReqDataBuilder setLimit_pay(String limit_pay) {
  217.   this.limit_pay = limit_pay;
  218.   return this;
  219. }

  220. public UnifiedOrderReqDataBuilder setOpenid(String openid) {
  221.   this.openid = openid;
  222.   return this;
  223. }


  224. public UnifiedOrderReqData build() {

  225.   if("JSAPI".equals(this.trade_type) && this.openid == null) {
  226.   throw new IllegalArgumentException("当传入trade_type为JSAPI时,openid为必填参数");
  227.   }
  228.   if("NATIVE".equals(this.trade_type) && this.product_id == null) {
  229.   throw new IllegalArgumentException("当传入trade_type为NATIVE时,product_id为必填参数");
  230.   }
  231.   return new UnifiedOrderReqData(this);
  232. }
  233. }



  234. }
复制代码

  因为有些参数为必填,有些参数为选填。而且sign要等所有参数传入之后才能计算的出,所以这里用了builder模式。关于builder模式。
  
  我们选用httpclient进行网络传输。
  1. package com.unstoppedable.common;

  2. import com.thoughtworks.xstream.XStream;
  3. import com.thoughtworks.xstream.io.xml.DomDriver;
  4. import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
  5. import org.apache.commons.logging.Log;
  6. import org.apache.commons.logging.LogFactory;
  7. import org.apache.http.HttpEntity;
  8. import org.apache.http.HttpResponse;
  9. import org.apache.http.client.ClientProtocolException;
  10. import org.apache.http.client.ResponseHandler;
  11. import org.apache.http.client.config.RequestConfig;
  12. import org.apache.http.client.methods.HttpGet;
  13. import org.apache.http.client.methods.HttpPost;
  14. import org.apache.http.conn.ConnectTimeoutException;
  15. import org.apache.http.conn.ConnectionPoolTimeoutException;
  16. import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
  17. import org.apache.http.conn.ssl.SSLContexts;
  18. import org.apache.http.entity.StringEntity;
  19. import org.apache.http.impl.client.CloseableHttpClient;
  20. import org.apache.http.impl.client.HttpClients;
  21. import org.apache.http.util.EntityUtils;

  22. import javax.net.ssl.SSLContext;
  23. import java.io.File;
  24. import java.io.FileInputStream;
  25. import java.io.IOException;
  26. import java.net.SocketTimeoutException;
  27. import java.security.KeyStore;

  28. /**
  29. * Created by hupeng on 2015/7/28.
  30. */
  31. public class HttpService {
  32. private static Log logger = LogFactory.getLog(HttpService.class);

  33. private static CloseableHttpClient httpClient = buildHttpClient();

  34. //连接超时时间,默认10秒
  35. private static int socketTimeout = 5000;

  36. //传输超时时间,默认30秒
  37. private static int connectTimeout = 5000;

  38. private static int requestTimeout = 5000;

  39. public static CloseableHttpClient buildHttpClient() {

  40. try {
  41.   KeyStore keyStore = KeyStore.getInstance("PKCS12");
  42.   FileInputStream instream = new FileInputStream(new File(Configure.getCertLocalPath()));//加载本地的证书进行https加密传输
  43.   try {
  44.   keyStore.load(instream, Configure.getCertPassword().toCharArray());//设置证书密码
  45.   } finally {
  46.   instream.close();
  47.   }


  48.   // Trust own CA and all self-signed certs
  49.   SSLContext sslcontext = SSLContexts.custom()
  50.    .loadKeyMaterial(keyStore, Configure.getCertPassword().toCharArray())
  51.    .build();
  52.   // Allow TLSv1 protocol only
  53.   SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
  54.    sslcontext,
  55.    new String[]{"TLSv1"},
  56.    null,
  57.    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

  58.   RequestConfig requestConfig = RequestConfig.custom()
  59.    .setConnectTimeout(connectTimeout)
  60.    .setConnectionRequestTimeout(requestTimeout)
  61.    .setSocketTimeout(socketTimeout).build();

  62.   httpClient = HttpClients.custom()
  63.    .setDefaultRequestConfig(requestConfig)
  64.    .setSSLSocketFactory(sslsf)
  65.    .build();

  66.   return httpClient;
  67. } catch (Exception e) {
  68.   throw new RuntimeException("error create httpclient......", e);
  69. }
  70. }



  71. public static String doGet(String requestUrl) throws Exception {
  72. HttpGet httpget = new HttpGet(requestUrl);
  73. try {


  74.   logger.debug("Executing request " + httpget.getRequestLine());
  75.   // Create a custom response handler
  76.   ResponseHandler<String> responseHandler = new ResponseHandler<String>() {

  77.   @Override
  78.   public String handleResponse(
  79.    final HttpResponse response) throws ClientProtocolException, IOException {
  80.    int status = response.getStatusLine().getStatusCode();
  81.    if (status >= 200 && status < 300) {
  82.    HttpEntity entity = response.getEntity();
  83.    return entity != null ? EntityUtils.toString(entity) : null;
  84.    } else {
  85.    throw new ClientProtocolException("Unexpected response status: " + status);
  86.    }
  87.   }

  88.   };

  89.   return httpClient.execute(httpget, responseHandler);
  90. } finally {
  91.   httpget.releaseConnection();
  92. }
  93. }

  94. public static String doPost(String url, Object object2Xml) {

  95. String result = null;

  96. HttpPost httpPost = new HttpPost(url);

  97. //解决XStream对出现双下划线的bug
  98. XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_")));

  99. //将要提交给API的数据对象转换成XML格式数据Post给API
  100. String postDataXML = xStreamForRequestPostData.toXML(object2Xml);

  101. logger.info("API,POST过去的数据是:");
  102. logger.info(postDataXML);

  103. //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
  104. StringEntity postEntity = new StringEntity(postDataXML, "UTF-8");
  105. httpPost.addHeader("Content-Type", "text/xml");
  106. httpPost.setEntity(postEntity);

  107. //设置请求器的配置

  108. logger.info("executing request" + httpPost.getRequestLine());

  109. try {
  110.   HttpResponse response = httpClient.execute(httpPost);

  111.   HttpEntity entity = response.getEntity();

  112.   result = EntityUtils.toString(entity, "UTF-8");

  113. } catch (ConnectionPoolTimeoutException e) {
  114.   logger.error("http get throw ConnectionPoolTimeoutException(wait time out)", e);

  115. } catch (ConnectTimeoutException e) {
  116.   logger.error("http get throw ConnectTimeoutException", e);

  117. } catch (SocketTimeoutException e) {
  118.   logger.error("http get throw SocketTimeoutException", e);

  119. } catch (Exception e) {
  120.   logger.error("http get throw Exception", e);

  121. } finally {
  122.   httpPost.abort();
  123. }

  124. return result;
  125. }
  126. }
复制代码

  然后是我们的总入口:
  1. package com.unstoppedable.service;

  2. import com.unstoppedable.common.Configure;
  3. import com.unstoppedable.common.HttpService;
  4. import com.unstoppedable.common.XMLParser;
  5. import com.unstoppedable.protocol.UnifiedOrderReqData;
  6. import org.xml.sax.SAXException;

  7. import javax.xml.parsers.ParserConfigurationException;
  8. import java.io.IOException;
  9. import java.util.Map;

  10. /**
  11. * Created by hupeng on 2015/7/28.
  12. */
  13. public class WxPayApi {

  14. public static Map<String,Object> UnifiedOrder(UnifiedOrderReqData reqData) throws IOException, SAXException, ParserConfigurationException {
  15. String res = HttpService.doPost(Configure.UNIFIED_ORDER_API, reqData);
  16. return XMLParser.getMapFromXML(res);
  17. }

  18. public static void main(String[] args) throws Exception {
  19. UnifiedOrderReqData reqData = new UnifiedOrderReqData.UnifiedOrderReqDataBuilder("appid", "mch_id", "body", "out_trade_no", 1, "spbill_create_ip", "notify_url", "JSAPI").setOpenid("openid").build();
  20. System.out.println(UnifiedOrder(reqData));


  21. }
  22. }
复制代码

  返回的xml为:
  1. <xml>
  2. <return_code><![CDATA[SUCCESS]]></return_code>
  3. <return_msg><![CDATA[OK]]></return_msg>
  4. <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
  5. <mch_id><![CDATA[10000100]]></mch_id>
  6. <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
  7. <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
  8. <result_code><![CDATA[SUCCESS]]></result_code>
  9. <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
  10. <trade_type><![CDATA[JSAPI]]></trade_type>
  11. </xml>
复制代码

  return_code 和result_code都为SUCCESS的时候会返回我们需要的prepay_id。。。,然后在jsapi中使用他就可以了。。
  
  以上就是本文的全部内容,希望对大家的学习有所帮助。

相关帖子

发表于 2017-1-17 14:17:59 | 显示全部楼层
有空一起交流一下
使用道具 举报

回复

发表于 2017-1-17 16:18:08 | 显示全部楼层
路过 帮顶 嘿嘿
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部