• 微信支付-公众号支付H5调用支付详解


    微信公众号支付

    最近项目需要微信支付,然后看了下微信公众号支付,,虽然不难,但是细节还是需要注意的,用了大半天时间写了个demo,并且完整的测试了一下支付流程,下面分享一下微信公众号支付的经验。


    一、配置公众号微信支付  

       需要我们配置微信公众号支付地址和测试白名单。

      

         比如:支付JS页面的地址为 http://www.xxx.com/shop/pay/

                那此处配置www.xxx.com/shop/pay/


      二、开发流程

         借用微信公众号支付api(地址 http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=7_4),我们需要开发的为红色标记出的。如下:

        

     

    三、向微信服务器端下订单

                 调用统一下单接口,这样就能获取微信支付的prepay_id(http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=9_1)。

         在调用该接口前有几个字段是H5支付必须填写的openid

        3.1 获取openid

             可以通过网页授权形式(http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html)

           在微信中发送如下链接

          

    https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=要跳转的下订单的url&response_type=code&scope=snsapi_base&state=123#wechat_redirect


       3.2 后台支付

        代码如下,包含预处理订单,支付订单等接口。

    1. package org.andy.controller;
    2. import java.io.ByteArrayInputStream;
    3. import java.io.IOException;
    4. import java.io.InputStream;
    5. import java.io.UnsupportedEncodingException;
    6. import java.util.Date;
    7. import java.util.HashMap;
    8. import java.util.Iterator;
    9. import java.util.Map;
    10. import java.util.Map.Entry;
    11. import java.util.Random;
    12. import javax.servlet.ServletInputStream;
    13. import javax.servlet.http.HttpServletRequest;
    14. import javax.servlet.http.HttpServletResponse;
    15. import org.apache.commons.codec.digest.DigestUtils;
    16. import org.springframework.stereotype.Controller;
    17. import org.springframework.web.bind.annotation.RequestMapping;
    18. import org.xmlpull.v1.XmlPullParser;
    19. import org.xmlpull.v1.XmlPullParserException;
    20. import org.xmlpull.v1.XmlPullParserFactory;
    21. import com.fasterxml.jackson.databind.JsonNode;
    22. import com.gson.oauth.Oauth;
    23. import com.gson.oauth.Pay;
    24. import com.gson.util.HttpKit;
    25. import com.gson.util.Tools;
    26. import org.andy.util.DatetimeUtil;
    27. import org.andy.util.JsonUtil;
    28. import org.andy.util.SessionUtil;
    29. import org.andy.util.WebUtil;
    30. @Controller
    31. @RequestMapping("/pay")
    32. public class WXPayController {
    33. @RequestMapping(value = "wxprepay")
    34. public void jspay(HttpServletRequest request, HttpServletResponse response, String callback) throws Exception {
    35. // 获取openid
    36. String openId = SessionUtil.getAtt(request, "openId");
    37. if (openId == null) {
    38. openId = getUserOpenId(request);
    39. }
    40. String appid = "wx16691fcb0523c1a4";
    41. String partnerid = "22223670";
    42. String paternerKey = "fjfjfjfjf1234567FFFFFFFFF1234567";
    43. String out_trade_no = getTradeNo();
    44. Map<String, String> paraMap = new HashMap<String, String>();
    45. paraMap.put("appid", appid);
    46. paraMap.put("attach", "测试支付");
    47. paraMap.put("body", "测试购买Beacon支付");
    48. paraMap.put("mch_id", partnerid);
    49. paraMap.put("nonce_str", create_nonce_str());
    50. paraMap.put("openid", openId);
    51. paraMap.put("out_trade_no", out_trade_no);
    52. paraMap.put("spbill_create_ip", getAddrIp(request));
    53. paraMap.put("total_fee", "1");
    54. paraMap.put("trade_type", "JSAPI");
    55. paraMap.put("notify_url", "http://www.xxx.co/wxpay/pay/appPay_notify.shtml");
    56. String sign = getSign(paraMap, paternerKey);
    57. paraMap.put("sign", sign);
    58. // 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
    59. String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    60. String xml = ArrayToXml(paraMap, false);
    61. String xmlStr = HttpKit.post(url, xml);
    62. // 预付商品id
    63. String prepay_id = "";
    64. if (xmlStr.indexOf("SUCCESS") != -1) {
    65. Map<String, String> map = doXMLParse(xmlStr);
    66. prepay_id = (String) map.get("prepay_id");
    67. }
    68. Map<String, String> payMap = new HashMap<String, String>();
    69. payMap.put("appId", appid);
    70. payMap.put("timeStamp", create_timestamp());
    71. payMap.put("nonceStr", create_nonce_str());
    72. payMap.put("signType", "MD5");
    73. payMap.put("package", "prepay_id=" + prepay_id);
    74. String paySign = getSign(payMap, paternerKey);
    75. payMap.put("pg", prepay_id);
    76. payMap.put("paySign", paySign);
    77. WebUtil.response(response, WebUtil.packJsonp(callback,
    78. JsonUtil.warpJsonNodeResponse(JsonUtil.objectToJsonNode(payMap)).toString()));
    79. }
    80. @RequestMapping(value = "appPay")
    81. public void appPay(HttpServletRequest request, HttpServletResponse response, String body, String detail,
    82. String total_fee, String spbill_create_ip, String notify_url, String trade_type, String callback)
    83. throws Exception {
    84. String appid = "wx16691fcb0523c1a4";
    85. String partnerid = "22223670";
    86. String paternerKey = "fjfjfjfjf1234567FFFFFFFFF1234567";
    87. String out_trade_no = getTradeNo();
    88. Map<String, String> paraMap = new HashMap<String, String>();
    89. paraMap.put("appid", appid);
    90. paraMap.put("body", body);
    91. paraMap.put("mch_id", partnerid);
    92. paraMap.put("nonce_str", create_nonce_str());
    93. paraMap.put("out_trade_no", out_trade_no);
    94. paraMap.put("spbill_create_ip", spbill_create_ip);
    95. paraMap.put("total_fee", total_fee);
    96. paraMap.put("trade_type", trade_type);
    97. paraMap.put("notify_url", notify_url);
    98. String sign = getSign(paraMap, paternerKey);
    99. paraMap.put("sign", sign);
    100. // 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
    101. String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    102. String xml = ArrayToXml(paraMap, false);
    103. String xmlStr = HttpKit.post(url, xml);
    104. // 预付商品id
    105. String prepay_id = "";
    106. Map<String, String> map = doXMLParse(xmlStr);
    107. if (xmlStr.indexOf("SUCCESS") != -1) {
    108. prepay_id = (String) map.get("prepay_id");
    109. }
    110. String result_code = map.get("result_code");
    111. String err_code_des = map.get("err_code_des");
    112. Map<String, String> payMap = new HashMap<String, String>();
    113. payMap.put("appid", appid);
    114. payMap.put("partnerid", partnerid);
    115. payMap.put("prepayid", prepay_id);
    116. payMap.put("package", "Sign=WXPay");
    117. payMap.put("noncestr", create_nonce_str());
    118. payMap.put("timestamp", create_timestamp());
    119. String paySign = getSign(payMap, paternerKey);
    120. payMap.put("sign", paySign);
    121. payMap.put("result_code", result_code);
    122. payMap.put("err_code_des", err_code_des);
    123. WebUtil.response(response, WebUtil.packJsonp(callback,
    124. JsonUtil.warpJsonNodeResponse(JsonUtil.objectToJsonNode(payMap)).toString()));
    125. }
    126. @RequestMapping("/appPay_notify")
    127. public void appPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
    128. // String xml =
    129. // "<xml><appid><![CDATA[wxb4dc385f953b356e]]></appid><bank_type><![CDATA[CCB_CREDIT]]></bank_type><cash_fee><![CDATA[1]]></cash_fee><fee_type><![CDATA[CNY]]></fee_type><is_subscribe><![CDATA[Y]]></is_subscribe><mch_id><![CDATA[1228442802]]></mch_id><nonce_str><![CDATA[1002477130]]></nonce_str><openid><![CDATA[o-HREuJzRr3moMvv990VdfnQ8x4k]]></openid><out_trade_no><![CDATA[1000000000051249]]></out_trade_no><result_code><![CDATA[SUCCESS]]></result_code><return_code><![CDATA[SUCCESS]]></return_code><sign><![CDATA[1269E03E43F2B8C388A414EDAE185CEE]]></sign><time_end><![CDATA[20150324100405]]></time_end><total_fee>1</total_fee><trade_type><![CDATA[JSAPI]]></trade_type><transaction_id><![CDATA[1009530574201503240036299496]]></transaction_id></xml>";
    130. response.setCharacterEncoding("UTF-8");
    131. response.setContentType("text/xml");
    132. ServletInputStream in = request.getInputStream();
    133. String xmlMsg = Tools.inputStream2String(in);
    134. Map<String, String> map = doXMLParse(xmlMsg);
    135. String return_code = map.get("return_code");
    136. String return_msg = map.get("return_msg");
    137. map = new HashMap<String, String>();
    138. map.put("return_code", return_code);
    139. map.put("return_msg", return_msg);
    140. // 响应xml
    141. String resXml = ArrayToXml(map, true);
    142. response.getWriter().write(resXml);
    143. }
    144. @RequestMapping("/orderquery")
    145. public void orderquery(HttpServletRequest request, HttpServletResponse response, String transaction_id,
    146. String out_trade_no, String callback) throws Exception {
    147. String url = "https://api.mch.weixin.qq.com/pay/orderquery";
    148. String appid = "wx16691fcb0523c1a4";
    149. String partnerid = "22223670";
    150. String paternerKey = "fjfjfjfjf1234567FFFFFFFFF1234567";
    151. Map<String, String> map = new HashMap<String, String>();
    152. map.put("appid", appid);
    153. map.put("mch_id", partnerid);
    154. if (transaction_id != null && !transaction_id.equals("")) {
    155. map.put("transaction_id", transaction_id);
    156. } else {
    157. map.put("out_trade_no", out_trade_no);
    158. }
    159. map.put("nonce_str", create_nonce_str());
    160. String paySign = getSign(map, paternerKey);
    161. map.put("sign", paySign);
    162. String xml = ArrayToXml(map, false);
    163. String xmlStr = HttpKit.post(url, xml);
    164. Map<String, String> orderMap = doXMLParse(xmlStr);
    165. WebUtil.response(response, WebUtil.packJsonp(callback,
    166. JsonUtil.warpJsonNodeResponse(JsonUtil.objectToJsonNode(orderMap)).toString()));
    167. }
    168. /**
    169. * map转成xml
    170. *
    171. * @param arr
    172. * @return
    173. */
    174. public String ArrayToXml(Map<String, String> parm, boolean isAddCDATA) {
    175. StringBuffer strbuff = new StringBuffer("<xml>");
    176. if (parm != null && !parm.isEmpty()) {
    177. for (Entry<String, String> entry : parm.entrySet()) {
    178. strbuff.append("<").append(entry.getKey()).append(">");
    179. if (isAddCDATA) {
    180. strbuff.append("<![CDATA[");
    181. if (StringUtil.isNotEmpty(entry.getValue())) {
    182. strbuff.append(entry.getValue());
    183. }
    184. strbuff.append("]]>");
    185. } else {
    186. if (StringUtil.isNotEmpty(entry.getValue())) {
    187. strbuff.append(entry.getValue());
    188. }
    189. }
    190. strbuff.append("</").append(entry.getKey()).append(">");
    191. }
    192. }
    193. return strbuff.append("</xml>").toString();
    194. }
    195. // 获取openId
    196. private String getUserOpenId(HttpServletRequest request) throws Exception {
    197. String code = request.getParameter("code");
    198. if (code == null) {
    199. String openId = request.getParameter("openId");
    200. return openId;
    201. }
    202. Oauth o = new Oauth();
    203. String token = o.getToken(code);
    204. JsonNode node = JsonUtil.StringToJsonNode(token);
    205. String openId = node.get("openid").asText();
    206. return openId;
    207. }
    208. private String create_nonce_str() {
    209. String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    210. String res = "";
    211. for (int i = 0; i < 16; i++) {
    212. Random rd = new Random();
    213. res += chars.charAt(rd.nextInt(chars.length() - 1));
    214. }
    215. return res;
    216. }
    217. private String getAddrIp(HttpServletRequest request) {
    218. return request.getRemoteAddr();
    219. }
    220. private String create_timestamp() {
    221. return Long.toString(System.currentTimeMillis() / 1000);
    222. }
    223. private String getTradeNo() {
    224. String timestamp = DatetimeUtil.formatDate(new Date(), DatetimeUtil.DATETIME_PATTERN);
    225. return "HZNO" + timestamp;
    226. }
    227. private String getSign(Map<String, String> params, String paternerKey) throws UnsupportedEncodingException {
    228. String string1 = Pay.createSign(params, false);
    229. String stringSignTemp = string1 + "&key=" + paternerKey;
    230. String signValue = DigestUtils.md5Hex(stringSignTemp).toUpperCase();
    231. return signValue;
    232. }
    233. private Map<String, String> doXMLParse(String xml) throws XmlPullParserException, IOException {
    234. InputStream inputStream = new ByteArrayInputStream(xml.getBytes());
    235. Map<String, String> map = null;
    236. XmlPullParser pullParser = XmlPullParserFactory.newInstance().newPullParser();
    237. pullParser.setInput(inputStream, "UTF-8"); // 为xml设置要解析的xml数据
    238. int eventType = pullParser.getEventType();
    239. while (eventType != XmlPullParser.END_DOCUMENT) {
    240. switch (eventType) {
    241. case XmlPullParser.START_DOCUMENT:
    242. map = new HashMap<String, String>();
    243. break;
    244. case XmlPullParser.START_TAG:
    245. String key = pullParser.getName();
    246. if (key.equals("xml"))
    247. break;
    248. String value = pullParser.nextText();
    249. map.put(key, value);
    250. break;
    251. case XmlPullParser.END_TAG:
    252. break;
    253. }
    254. eventType = pullParser.next();
    255. }
    256. return map;
    257. }
    258. }

     


    
    

      wxprepay.shtm接口是预处理订单接口向微信服务器下订单。

      appPay.shtml接口是支付接口。

      appPay_notify.shtml接口是微信支付后异步通知结果接口。

      orderquery.shtml接口是订单查询接口

    3.3、涉及到的工具类

        SessionUtil.java工具类

    1. package org.andy.util;
    2. import javax.servlet.http.HttpServletRequest;
    3. public class SessionUtil {
    4. public static void addAtt(HttpServletRequest request, String key, Object value){
    5. request.getSession().setAttribute(key, value);
    6. }
    7. public static void removeAtt(HttpServletRequest request, String key){
    8. request.getSession().removeAttribute(key);
    9. }
    10. public static String getAtt(HttpServletRequest request, String key){
    11. return (String)request.getSession().getAttribute(key);
    12. }
    13. public static Object getAttObj(HttpServletRequest request, String key){
    14. return request.getSession().getAttribute(key);
    15. }
    16. public static String optAtt(HttpServletRequest request, String key, String value){
    17. String r = (String)request.getSession().getAttribute(key);
    18. if (r == null){
    19. r = value;
    20. }
    21. return r;
    22. }
    23. }

    HttpKit 网络请求工具类

    1. /**
    2. * https 请求 微信为https的请求
    3. *
    4. * @author andy
    5. * @date 2015-10-9 下午2:40:19
    6. */
    7. public class HttpKit {
    8. private static final String DEFAULT_CHARSET = "UTF-8";
    9. /**
    10. * @return 返回类型:
    11. * @throws IOException
    12. * @throws UnsupportedEncodingException
    13. * @throws NoSuchProviderException
    14. * @throws NoSuchAlgorithmException
    15. * @throws KeyManagementException
    16. * @description 功能描述: get 请求
    17. */
    18. public static String get(String url, Map<String, String> params, Map<String, String> headers) throws IOException, ExecutionException, InterruptedException {
    19. AsyncHttpClient http = new AsyncHttpClient();
    20. AsyncHttpClient.BoundRequestBuilder builder = http.prepareGet(url);
    21. builder.setBodyEncoding(DEFAULT_CHARSET);
    22. if (params != null && !params.isEmpty()) {
    23. Set<String> keys = params.keySet();
    24. for (String key : keys) {
    25. builder.addQueryParameter(key, params.get(key));
    26. }
    27. }
    28. if (headers != null && !headers.isEmpty()) {
    29. Set<String> keys = headers.keySet();
    30. for (String key : keys) {
    31. builder.addHeader(key, params.get(key));
    32. }
    33. }
    34. Future<Response> f = builder.execute();
    35. String body = f.get().getResponseBody(DEFAULT_CHARSET);
    36. http.close();
    37. return body;
    38. }
    39. /**
    40. * @return 返回类型:
    41. * @throws IOException
    42. * @throws UnsupportedEncodingException
    43. * @throws NoSuchProviderException
    44. * @throws NoSuchAlgorithmException
    45. * @throws KeyManagementException
    46. * @description 功能描述: get 请求
    47. */
    48. public static String get(String url) throws KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException, UnsupportedEncodingException, IOException, ExecutionException, InterruptedException {
    49. return get(url, null);
    50. }
    51. /**
    52. * @return 返回类型:
    53. * @throws IOException
    54. * @throws NoSuchProviderException
    55. * @throws NoSuchAlgorithmException
    56. * @throws KeyManagementException
    57. * @throws UnsupportedEncodingException
    58. * @description 功能描述: get 请求
    59. */
    60. public static String get(String url, Map<String, String> params) throws KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException, UnsupportedEncodingException, IOException, ExecutionException, InterruptedException {
    61. return get(url, params, null);
    62. }
    63. /**
    64. * @return 返回类型:
    65. * @throws IOException
    66. * @throws NoSuchProviderException
    67. * @throws NoSuchAlgorithmException
    68. * @throws KeyManagementException
    69. * @description 功能描述: POST 请求
    70. */
    71. public static String post(String url, Map<String, String> params) throws IOException, ExecutionException, InterruptedException {
    72. AsyncHttpClient http = new AsyncHttpClient();
    73. AsyncHttpClient.BoundRequestBuilder builder = http.preparePost(url);
    74. builder.setBodyEncoding(DEFAULT_CHARSET);
    75. if (params != null && !params.isEmpty()) {
    76. Set<String> keys = params.keySet();
    77. for (String key : keys) {
    78. builder.addParameter(key, params.get(key));
    79. }
    80. }
    81. Future<Response> f = builder.execute();
    82. String body = f.get().getResponseBody(DEFAULT_CHARSET);
    83. http.close();
    84. return body;
    85. }
    86. public static String post(String url, String s) throws IOException, ExecutionException, InterruptedException {
    87. AsyncHttpClient http = new AsyncHttpClient();
    88. AsyncHttpClient.BoundRequestBuilder builder = http.preparePost(url);
    89. builder.setBodyEncoding(DEFAULT_CHARSET);
    90. builder.setBody(s);
    91. Future<Response> f = builder.execute();
    92. String body = f.get().getResponseBody(DEFAULT_CHARSET);
    93. http.close();
    94. return body;
    95. }
    96. }

    支付工具类pay.java

    1. /**
    2. * 支付相关方法
    3. * @author andy
    4. *
    5. */
    6. public class Pay {
    7. // 发货通知接口
    8. private static final String DELIVERNOTIFY_URL = "https://api.weixin.qq.com/pay/delivernotify?access_token=";
    9. /**
    10. * 参与 paySign 签名的字段包括:appid、timestamp、noncestr、package 以及 appkey。
    11. * 这里 signType 并不参与签名微信的Package参数
    12. * @param params
    13. * @return
    14. * @throws UnsupportedEncodingException
    15. */
    16. public static String getPackage(Map<String, String> params) throws UnsupportedEncodingException {
    17. String partnerKey = ConfKit.get("partnerKey");
    18. String partnerId = ConfKit.get("partnerId");
    19. String notifyUrl = ConfKit.get("notify_url");
    20. // 公共参数
    21. params.put("bank_type", "WX");
    22. params.put("attach", "yongle");
    23. params.put("partner", partnerId);
    24. params.put("notify_url", notifyUrl);
    25. params.put("input_charset", "UTF-8");
    26. return packageSign(params, partnerKey);
    27. }
    28. /**
    29. * 构造签名
    30. * @param params
    31. * @param encode
    32. * @return
    33. * @throws UnsupportedEncodingException
    34. */
    35. public static String createSign(Map<String, String> params, boolean encode) throws UnsupportedEncodingException {
    36. Set<String> keysSet = params.keySet();
    37. Object[] keys = keysSet.toArray();
    38. Arrays.sort(keys);
    39. StringBuffer temp = new StringBuffer();
    40. boolean first = true;
    41. for (Object key : keys) {
    42. if (key == null || StringUtil.isEmpty(params.get(key))) // 参数为空参与签名
    43. continue;
    44. if (first) {
    45. first = false;
    46. } else {
    47. temp.append("&");
    48. }
    49. temp.append(key).append("=");
    50. Object value = params.get(key);
    51. String valueString = "";
    52. if (null != value) {
    53. valueString = value.toString();
    54. }
    55. if (encode) {
    56. temp.append(URLEncoder.encode(valueString, "UTF-8"));
    57. } else {
    58. temp.append(valueString);
    59. }
    60. }
    61. return temp.toString();
    62. }
    63. /**
    64. * @param params
    65. * @param paternerKey
    66. * @return
    67. * @throws UnsupportedEncodingException
    68. */
    69. private static String packageSign(Map<String, String> params, String paternerKey) throws UnsupportedEncodingException {
    70. String string1 = createSign(params, false);
    71. String stringSignTemp = string1 + "&key=" + paternerKey;
    72. String signValue = DigestUtils.md5Hex(stringSignTemp).toUpperCase();
    73. String string2 = createSign(params, true);
    74. return string2 + "&sign=" + signValue;
    75. }
    76. /**
    77. * 支付签名
    78. * @param timestamp
    79. * @param noncestr
    80. * @param packages
    81. * @return
    82. * @throws UnsupportedEncodingException
    83. */
    84. public static String paySign(String timestamp, String noncestr,String packages) throws UnsupportedEncodingException {
    85. Map<String, String> paras = new HashMap<String, String>();
    86. paras.put("appid", ConfKit.get("AppId"));
    87. paras.put("timestamp", timestamp);
    88. paras.put("noncestr", noncestr);
    89. paras.put("package", packages);
    90. paras.put("appkey", ConfKit.get("paySignKey"));
    91. // appid、timestamp、noncestr、package 以及 appkey。
    92. String string1 = createSign(paras, false);
    93. String paySign = DigestUtils.shaHex(string1);
    94. return paySign;
    95. }
    96. /**
    97. * 支付回调校验签名
    98. * @param timestamp
    99. * @param noncestr
    100. * @param openid
    101. * @param issubscribe
    102. * @param appsignature
    103. * @return
    104. * @throws UnsupportedEncodingException
    105. */
    106. public static boolean verifySign(long timestamp,
    107. String noncestr, String openid, int issubscribe, String appsignature) throws UnsupportedEncodingException {
    108. Map<String, String> paras = new HashMap<String, String>();
    109. paras.put("appid", ConfKit.get("AppId"));
    110. paras.put("appkey", ConfKit.get("paySignKey"));
    111. paras.put("timestamp", String.valueOf(timestamp));
    112. paras.put("noncestr", noncestr);
    113. paras.put("openid", openid);
    114. paras.put("issubscribe", String.valueOf(issubscribe));
    115. // appid、appkey、productid、timestamp、noncestr、openid、issubscribe
    116. String string1 = createSign(paras, false);
    117. String paySign = DigestUtils.shaHex(string1);
    118. return paySign.equalsIgnoreCase(appsignature);
    119. }
    120. /**
    121. * 发货通知签名
    122. * @param paras
    123. * @return
    124. * @throws UnsupportedEncodingException
    125. *
    126. * @参数 appid、appkey、openid、transid、out_trade_no、deliver_timestamp、deliver_status、deliver_msg;
    127. */
    128. private static String deliverSign(Map<String, String> paras) throws UnsupportedEncodingException {
    129. paras.put("appkey", ConfKit.get("paySignKey"));
    130. String string1 = createSign(paras, false);
    131. String paySign = DigestUtils.shaHex(string1);
    132. return paySign;
    133. }
    134. /**
    135. * 发货通知
    136. * @param access_token
    137. * @param openid
    138. * @param transid
    139. * @param out_trade_no
    140. * @return
    141. * @throws IOException
    142. * @throws NoSuchProviderException
    143. * @throws NoSuchAlgorithmException
    144. * @throws KeyManagementException
    145. * @throws InterruptedException
    146. * @throws ExecutionException
    147. */
    148. public static boolean delivernotify(String access_token, String openid, String transid, String out_trade_no) throws IOException, ExecutionException, InterruptedException {
    149. Map<String, String> paras = new HashMap<String, String>();
    150. paras.put("appid", ConfKit.get("AppId"));
    151. paras.put("openid", openid);
    152. paras.put("transid", transid);
    153. paras.put("out_trade_no", out_trade_no);
    154. paras.put("deliver_timestamp", (System.currentTimeMillis() / 1000) + "");
    155. paras.put("deliver_status", "1");
    156. paras.put("deliver_msg", "ok");
    157. // 签名
    158. String app_signature = deliverSign(paras);
    159. paras.put("app_signature", app_signature);
    160. paras.put("sign_method", "sha1");
    161. String json = HttpKit.post(DELIVERNOTIFY_URL.concat(access_token), JSONObject.toJSONString(paras));
    162. if (StringUtils.isNotBlank(json)) {
    163. JSONObject object = JSONObject.parseObject(json);
    164. if (object.containsKey("errcode")) {
    165. int errcode = object.getIntValue("errcode");
    166. return errcode == 0;
    167. }
    168. }
    169. return false;
    170. }
    171. }

    流转化Tools.java工具类

    1. public final class Tools {
    2. public static final String inputStream2String(InputStream in) throws UnsupportedEncodingException, IOException{
    3. if(in == null)
    4. return "";
    5. StringBuffer out = new StringBuffer();
    6. byte[] b = new byte[4096];
    7. for (int n; (n = in.read(b)) != -1;) {
    8. out.append(new String(b, 0, n, "UTF-8"));
    9. }
    10. return out.toString();
    11. }
    12. public static final boolean checkSignature(String token,String signature,String timestamp,String nonce){
    13. List<String> params = new ArrayList<String>();
    14. params.add(token);
    15. params.add(timestamp);
    16. params.add(nonce);
    17. Collections.sort(params,new Comparator<String>() {
    18. @Override
    19. public int compare(String o1, String o2) {
    20. return o1.compareTo(o2);
    21. }
    22. });
    23. String temp = params.get(0)+params.get(1)+params.get(2);
    24. return SHA1.encode(temp).equals(signature);
    25. }
    26. }

    相应前端数据工具WebUtil.java工具类

    1. public class WebUtil {
    2. public static Object getSessionAttribute(HttpServletRequest req, String key) {
    3. Object ret = null;
    4. try {
    5. ret = req.getSession(false).getAttribute(key);
    6. } catch (Exception e) {
    7. }
    8. return ret;
    9. }
    10. public static void response(HttpServletResponse response, String result) {
    11. try {
    12. response.setContentType("application/json;charset=utf-8");
    13. response.getWriter().write(result);
    14. } catch (IOException e) {
    15. e.printStackTrace();
    16. }
    17. }
    18. public static void response(HttpServletResponse response, ResponseMessage result) {
    19. try {
    20. response.setContentType("application/json;charset=utf-8");
    21. response.getWriter().write(JsonUtil.objectToJsonNode(result).toString());
    22. } catch (Exception e) {
    23. e.printStackTrace();
    24. }
    25. }
    26. public static String packJsonp(String callback, String json) {
    27. if (json == null) {
    28. json = "";
    29. }
    30. if (callback == null || callback.isEmpty()) {
    31. return json;
    32. }
    33. return callback + "&&" + callback + '(' + json + ')';
    34. }
    35. public static String packJsonp(String callback, ResponseMessage response) {
    36. String json = null;
    37. if (response == null) {
    38. json = "";
    39. } else {
    40. json = JsonUtil.objectToJsonNode(response).toString();
    41. }
    42. if (callback == null || callback.isEmpty()) {
    43. return json;
    44. }
    45. return callback + "&&" + callback + '(' + json + ')';
    46. }
    47. }

    Json转换工具JsonUtil.java

    1. public class JsonUtil {
    2. public static ObjectNode warpJsonNodeResponse(JsonNode obj){
    3. ObjectNode objectNode=createObjectNode();
    4. objectNode.put("code", 1);
    5. objectNode.put("response", obj);
    6. return objectNode;
    7. }
    8. public static JsonNode objectToJsonNode(Object obj){
    9. try {
    10. ObjectMapper objectMapper = new ObjectMapper();
    11. String objJson=objectMapper.writeValueAsString(obj);
    12. JsonNode jsonNode = objectMapper.readTree(objJson);
    13. return jsonNode;
    14. } catch (JsonProcessingException e) {
    15. e.printStackTrace();
    16. } catch (IOException e) {
    17. // TODO Auto-generated catch block
    18. e.printStackTrace();
    19. }
    20. return null;
    21. }
    22. }



    四、微信H5调起支付

     这个url需要后台实现,其实现功能如下:

             1、接受微信服务器端发送的支付结果。

             2、向微信服务器发送支付结果

             具体 参考微信aip(http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=9_7)

           

          具体代码如下:

    4.1、授权向后台发起生成统一下订单页面

    wxrepay.jsp

    1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    2. <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
    3. <%
    4. String path = request.getContextPath();
    5. String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
    6. long t = System.currentTimeMillis();
    7. %>
    8. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    9. <html>
    10. <head>
    11. <meta charset="utf-8" />
    12. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
    13. <meta name="apple-mobile-web-app-capable" content="yes" />
    14. <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    15. <meta name="format-detection" content="telephone=no" />
    16. <title>微信公众号支付</title>
    17. <link href="../css/css.css?t=<%=t%>" rel="stylesheet" type="text/css">
    18. </head>
    19. <body>
    20. <div class="index_box">
    21. <div class="apply_name">商品</div>
    22. <div class="branch_con">
    23. <ul>
    24. <li><span class="name">beacon 1分钱 1只</span></li>
    25. <li><span class="name">测试支付信息</span></li>
    26. </ul>
    27. <p class="cz_btn"><a href="javascript:reppay();" class="btn_1">确定购买</a></p>
    28. </div>
    29. </div>
    30. <script type="text/javascript" src="../js/common.js?t=<%=t%>"></script>
    31. <script type="text/javascript" >
    32. var code = urlparameter("code");
    33. function reppay(){
    34. ajaxUtil({}, mainpath+"/pay/wxprepay.shtml?code=" + code, repay);
    35. }
    36. function repay(response){
    37. var info = response;
    38. var url = "wxpay?appId=" + info.appId + "&timeStamp=" +info.timeStamp + "&nonceStr=" + info.nonceStr +
    39. "&pg=" +info.pg + "&signType=" +info.signType + "&paySign=" +info.paySign;
    40. window.location.href= url + "&showwxpaytitle=1";
    41. }
    42. </script>
    43. </body>
    44. </html>

    首先是请求服务端wxprepay.shml接口,后台向微信支付平台获取支付订单信息,返回前台,wxpay.jsp页面

    4.2、确认支付页面

    1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    2. <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
    3. <%
    4. String path = request.getContextPath();
    5. String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
    6. long t = System.currentTimeMillis();
    7. %>
    8. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    9. <html>
    10. <head>
    11. <meta charset="utf-8" />
    12. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
    13. <meta name="apple-mobile-web-app-capable" content="yes" />
    14. <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    15. <meta name="format-detection" content="telephone=no" />
    16. <title>微信公众号支付</title>
    17. <link href="../css/css.css?t=<%=t%>" rel="stylesheet" type="text/css">
    18. </head>
    19. <body>
    20. <div class="index_box">
    21. <div class="apply_name">微信js支付测试</div>
    22. <div class="branch_con">
    23. <ul>
    24. <li><span class="name">测试支付信息</span></li>
    25. </ul>
    26. <p class="cz_btn"><a href="javascript:pay();" class="btn_1">立即支付</a></p>
    27. </div>
    28. </div>
    29. <script type="text/javascript" src="../js/common.js?t=<%=t%>"></script>
    30. <script type="text/javascript">
    31. var appId = urlparameter("appId");
    32. var timeStamp = urlparameter("timeStamp");
    33. var nonceStr = urlparameter("nonceStr");
    34. var pg = urlparameter("pg");
    35. var signType = urlparameter("signType");
    36. var paySign = urlparameter("paySign");
    37. function onBridgeReady(){
    38. WeixinJSBridge.invoke(
    39. 'getBrandWCPayRequest', {
    40. "appId" : appId, //公众号名称,由商户传入
    41. "timeStamp": timeStamp, //时间戳,自1970年以来的秒数
    42. "nonceStr" : nonceStr, //随机串
    43. "package" : "prepay_id=" + pg,
    44. "signType" : signType, //微信签名方式:
    45. "paySign" : paySign //微信签名
    46. },
    47. function(res){
    48. if(res.err_msg == "get_brand_wcpay_request:ok" ) {
    49. alert("支付成功");
    50. } // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
    51. }
    52. );
    53. }
    54. function pay(){
    55. if (typeof WeixinJSBridge == "undefined"){
    56. if( document.addEventListener ){
    57. document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
    58. }else if (document.attachEvent){
    59. document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
    60. document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
    61. }
    62. }else{
    63. onBridgeReady();
    64. }
    65. }
    66. </script>
    67. </body>
    68. </html>


    4.2、前台涉及到的工具类

    javascript工具类common.js,样式css.css就不贴了没意义。

    1. var path="wxpay";
    2. var mainpath = "/wxpay";
    3. var appid = "wx16691fcb0523c1a4";
    4. var urlpre = "http://www.xxx.com/wxpay/page";
    5. var urlhost = "http://www.xxx.com/";
    6. $(document).ready(function(){
    7. $(".refresher").click(function(){
    8. refresh();
    9. });
    10. $("#goback").click(function(){
    11. goback();
    12. });
    13. });
    14. function popupMsg(msg){
    15. alert(msg);
    16. }
    17. function printUtilViaGet(panel, requestdata, ajaxurl, printfunction){
    18. $.ajax({
    19. type: 'GET',
    20. url: ajaxurl,
    21. data: requestdata,
    22. cache:false,
    23. dataType:"json",
    24. async: false,
    25. success: function(response) {
    26. if (response.code){
    27. if (panel != null && panel.length > 0){
    28. $(panel).html("");
    29. if (printfunction != null)
    30. $(panel).html(printfunction(response.response));
    31. }
    32. return true;
    33. } else {
    34. //alert(response.reason);
    35. }
    36. },
    37. error: function(x, e) {
    38. //alert("error", x);
    39. },
    40. complete: function(x) {
    41. //alert("call complete");
    42. }
    43. });
    44. return false;
    45. }
    46. function ajaxUtilViaGet(requestdata, ajaxurl, succFunction, failFunction){
    47. $.ajax({
    48. url: ajaxurl,
    49. type: "GET",
    50. dataType: "json",
    51. cache:false,
    52. data: requestdata,
    53. async: false,
    54. success: function(response) {
    55. if (response.code){
    56. if (succFunction != null)
    57. succFunction(response.response);
    58. } else {
    59. if (failFunction != null)
    60. failFunction(response.response);
    61. }
    62. },
    63. error: function(x, e) {
    64. //alert("error", x);
    65. },
    66. complete: function(x) {
    67. }
    68. });
    69. return false;
    70. }
    71. function printUtil(panel, requestdata, ajaxurl, printfunction, ajaxasync) {
    72. if (isEmpty(ajaxasync)) {
    73. ajaxasync = false;
    74. }
    75. $.ajax({
    76. type : 'POST',
    77. url : ajaxurl,
    78. data : requestdata,
    79. cache : false,
    80. dataType : "json",
    81. async : ajaxasync,
    82. success : function(response) {
    83. if (response.code) {
    84. if (panel != null && panel.length > 0) {
    85. $(panel).html("");
    86. if (printfunction != null)
    87. $(panel).html(printfunction(response.response));
    88. }
    89. return true;
    90. } else {
    91. // alert(response.reason);
    92. }
    93. },
    94. error : function(x, e) {
    95. // alert("error", x);
    96. },
    97. complete : function(x) {
    98. // alert("call complete");
    99. }
    100. });
    101. return false;
    102. }
    103. function appendUtil(panel, requestdata, ajaxurl, printfunction, ajaxasync) {
    104. if (isEmpty(ajaxasync)) {
    105. ajaxasync = false;
    106. }
    107. $.ajax({
    108. type : 'POST',
    109. url : ajaxurl,
    110. data : requestdata,
    111. cache : false,
    112. dataType : "json",
    113. async : ajaxasync,
    114. success : function(response) {
    115. if (response.code) {
    116. if (panel != null && panel.length > 0) {
    117. if (printfunction != null)
    118. $(panel).append(printfunction(response.response));
    119. }
    120. return true;
    121. } else {
    122. // alert(response.reason);
    123. }
    124. },
    125. error : function(x, e) {
    126. // alert("error", x);
    127. },
    128. complete : function(x) {
    129. // alert("call complete");
    130. }
    131. });
    132. return false;
    133. }
    134. function ajaxUtilAsync(requestdata, ajaxurl, succFunction, failFunction) {
    135. $.ajax({
    136. url : ajaxurl,
    137. type : "POST",
    138. dataType : "json",
    139. cache : false,
    140. data : requestdata,
    141. async : true,
    142. success : function(response) {
    143. if (typeof response.code == "number") {
    144. if (response.code > 0) {
    145. if (succFunction != null)
    146. succFunction(response.response);
    147. } else {
    148. if (failFunction != null)
    149. failFunction(response.response);
    150. }
    151. } else {
    152. if (response.result) {
    153. if (succFunction != null)
    154. succFunction(response.response);
    155. } else {
    156. if (failFunction != null)
    157. failFunction(response.response);
    158. }
    159. }
    160. },
    161. error : function(x, e) {
    162. // alert("error", x);
    163. },
    164. complete : function(x) {
    165. }
    166. });
    167. return false;
    168. }
    169. function ajaxUtil(requestdata, ajaxurl, succFunction, failFunction){
    170. $.ajax({
    171. url: ajaxurl,
    172. type: "POST",
    173. dataType: "json",
    174. cache:false,
    175. data: requestdata,
    176. async: false,
    177. success: function(response) {
    178. if (typeof response.code == "number"){
    179. if (response.code > 0){
    180. if (succFunction != null)
    181. succFunction(response.response);
    182. } else {
    183. if (failFunction != null)
    184. failFunction(response.response);
    185. }
    186. } else {
    187. if (response.result){
    188. if (succFunction != null)
    189. succFunction(response.response);
    190. } else {
    191. if (failFunction != null)
    192. failFunction(response.response);
    193. }
    194. }
    195. },
    196. error: function(x, e) {
    197. //alert("error", x);
    198. },
    199. complete: function(x) {
    200. }
    201. });
    202. return false;
    203. }
    204. function loadSelection(panel, requestdata, ajaxurl, itemName){
    205. ajaxUtil(requestdata, ajaxurl, function(response){
    206. var list = response.list;
    207. for (var i = 0;i<list.length;i++){
    208. $(panel).append("<option value='"+list[i][itemName]+"'>"+list[i][itemName]+"</option>");
    209. }
    210. }, null);
    211. }
    212. function ajaxSubmitRefresh(formId) {
    213. var hideForm = $(formId);
    214. var options = {
    215. dataType : "json",
    216. beforeSubmit : function() {
    217. },
    218. success : function(result) {
    219. if (result.result){
    220. showMsg("提交成功");
    221. } else {
    222. alert("提交失败!");
    223. }
    224. },
    225. error : function(result) {
    226. alert("提交失败!");
    227. }
    228. };
    229. hideForm.ajaxSubmit(options);
    230. }
    231. function ajaxSubmitWithJump(formId, nextPage) {
    232. var hideForm = $(formId);
    233. var options = {
    234. dataType : "json",
    235. beforeSubmit : function() {
    236. },
    237. success : function(result) {
    238. if (result.result){
    239. alert("提交成功");
    240. window.location.href = nextPage;
    241. } else {
    242. alert("提交失败!");
    243. }
    244. },
    245. error : function(result) {
    246. alert("提交失败!");
    247. }
    248. };
    249. hideForm.ajaxSubmit(options);
    250. }
    251. function refresh(){
    252. window.location.href = window.location.href;
    253. }
    254. function goback(){
    255. history.go(-1);
    256. }
    257. function urlparameter(paras){
    258. var url = location.href;
    259. var paraString = url.substring(url.indexOf("?")+1,url.length).split("&");
    260. var paraObj = {};
    261. for (var i=0; j=paraString[i]; i++){
    262. paraObj[j.substring(0,j.indexOf("=")).toLowerCase()] = j.substring(j.indexOf("=")+1,j.length);
    263. }
    264. var returnValue = paraObj[paras.toLowerCase()];
    265. if(typeof(returnValue)=="undefined"){
    266. return "";
    267. }else{
    268. return returnValue;
    269. }
    270. }
    271. String.prototype.endWith=function(str){
    272. if(str==null||str==""||this.length==0||str.length>this.length)
    273. return false;
    274. if(this.substring(this.length-str.length)==str)
    275. return true;
    276. else
    277. return false;
    278. return true;
    279. };
    280. String.prototype.startWith=function(str){
    281. if(str==null||str==""||this.length==0||str.length>this.length)
    282. return false;
    283. if(this.substr(0,str.length)==str)
    284. return true;
    285. else
    286. return false;
    287. return true;
    288. };
    289. function getFileUrl(sourceId) {
    290. var url = "";
    291. if (navigator.userAgent.indexOf("MSIE")>=1) { // IE
    292. url = document.getElementById(sourceId).value;
    293. } else if(navigator.userAgent.indexOf("Firefox")>0) { // Firefox
    294. url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0));
    295. } else if(navigator.userAgent.indexOf("Chrome")>0) { // Chrome
    296. url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0));
    297. }
    298. return url;
    299. }
    300. function preImg(sourceId, targetId) {
    301. var url = getFileUrl(sourceId);
    302. var imgPre = document.getElementById(targetId);
    303. imgPre.src = url;
    304. }
    305. function initWX(){
    306. $.ajax({
    307. url:mainpath+'/wechatjs.do',
    308. type:'POST',
    309. dataType:'json',
    310. async: false,
    311. data: {url:location.href.split('#')[0]},
    312. success:function(result){
    313. console.log(result);
    314. var data=result['response']['map'];
    315. if(result['code']==1){
    316. wx.config({
    317. debug: false,
    318. appId:data['appId'],
    319. timestamp:data['timestamp'],
    320. nonceStr:data['nonceStr'],
    321. signature:data['signature'],
    322. jsApiList: ['onMenuShareTimeline','onMenuShareAppMessage','getLocation', 'onMenuShareQQ', 'onMenuShareWeibo']
    323. });
    324. }else{
    325. alert("fail to get code");
    326. window.alert('fail');
    327. };
    328. }
    329. });
    330. }
    331. var EARTH_RADIUS = 6378137.0; //单位M
    332. var PI = Math.PI;
    333. function getRad(d){
    334. return d*PI/180.0;
    335. }
    336. function getGreatCircleDistance(lat1,lng1,lat2,lng2){
    337. var radLat1 = getRad(lat1);
    338. var radLat2 = getRad(lat2);
    339. var a = radLat1 - radLat2;
    340. var b = getRad(lng1) - getRad(lng2);
    341. var s = 2*Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) + Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
    342. s = s*EARTH_RADIUS;
    343. s = Math.round(s*10000)/10000.0;
    344. s = Math.round(s);
    345. return s;
    346. }
    347. //对Date的扩展,将 Date 转化为指定格式的String
    348. //月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
    349. //年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
    350. //例子:
    351. //(new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
    352. //(new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
    353. Date.prototype.format = function(fmt)
    354. { //author: meizz
    355. var o = {
    356. "M+" : this.getMonth()+1, //月份
    357. "d+" : this.getDate(), //日
    358. "h+" : this.getHours(), //小时
    359. "m+" : this.getMinutes(), //分
    360. "s+" : this.getSeconds(), //秒
    361. "q+" : Math.floor((this.getMonth()+3)/3), //季度
    362. "S" : this.getMilliseconds() //毫秒
    363. };
    364. if(/(y+)/.test(fmt))
    365. fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
    366. for(var k in o)
    367. if(new RegExp("("+ k +")").test(fmt))
    368. fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
    369. return fmt;
    370. };
    371. //判断为空
    372. function isEmpty(src){
    373. if(("undefined" == typeof src) || (src == null) || ($.trim(src) == "") ){
    374. return true;
    375. }
    376. return false;
    377. }
    378. //判断不为空
    379. function notEmpty(src){
    380. return !isEmpty(src);
    381. }
    382. //微信页面授权 snsapi_base方式
    383. function wecharauto2burl(url) {
    384. return "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appid
    385. + "&redirect_uri=" + encodeURIComponent(url)
    386. + "&response_type=code&scope=snsapi_base&state=xybank#wechat_redirect";
    387. }
    388. //页面授权针对snsapi_base方式授权的url
    389. function wecharauto2baseurl(url) {
    390. return wecharauto2burl(urlpre+url);
    391. }
    392. //页面授权针对snsapi_userinfo方式授权的url
    393. function wecharauto2userinfourl(url) {
    394. return "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appid
    395. + "&redirect_uri=" + encodeURIComponent(urlpre+url)
    396. + "&response_type=code&scope=snsapi_userinfo&state=xybank#wechat_redirect";
    397. }
    398. //微信分享 此方法需放在wx.ready中
    399. function shareWeChat(title, link, imgUrl, desc){
    400. wx.onMenuShareTimeline({
    401. title: title, // 分享标题
    402. link: link, // 分享链接
    403. imgUrl: imgUrl, // 分享图标
    404. success: function () {
    405. // 用户确认分享后执行的回调函数
    406. },
    407. cancel: function () {
    408. // 用户取消分享后执行的回调函数
    409. }
    410. });
    411. //分享给朋友
    412. wx.onMenuShareAppMessage({
    413. title: title, // 分享标题
    414. desc: desc, // 分享描述
    415. link: link, // 分享链接
    416. imgUrl: imgUrl, // 分享图标
    417. type: 'link', // 分享类型,music、video或link,不填默认为link
    418. dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
    419. success: function () {
    420. // 用户确认分享后执行的回调函数
    421. },
    422. cancel: function () {
    423. // 用户取消分享后执行的回调函数
    424. }
    425. });
    426. //分享到QQ
    427. wx.onMenuShareQQ({
    428. title: title, // 分享标题
    429. desc: desc, // 分享描述
    430. link: link, // 分享链接
    431. imgUrl: imgUrl, // 分享图标
    432. success: function () {
    433. // 用户确认分享后执行的回调函数
    434. },
    435. cancel: function () {
    436. // 用户取消分享后执行的回调函数
    437. }
    438. });
    439. //分享到腾讯微博
    440. wx.onMenuShareWeibo({
    441. title: title, // 分享标题
    442. desc: desc, // 分享描述
    443. link: link, // 分享链接
    444. imgUrl: imgUrl, // 分享图标
    445. success: function () {
    446. // 用户确认分享后执行的回调函数
    447. },
    448. cancel: function () {
    449. // 用户取消分享后执行的回调函数
    450. }
    451. });
    452. }


    五、支付结果

     公众号调起效果如下:



    支付成功后,微信服务器得到后台的Notify通知后,会发微信说明支付信息,支付凭证如下:



    后续会全部更新微信app支付,微信支付退款,微信企业向个人付款,支付宝相关支付。而且会上传全部代码到csdn资源下载处。



  • 相关阅读:
    命令行打开控制面板
    开博纪念
    sql优化之 with as
    RMI 异常 no security manager: RMI class loader disabled
    C# MessageBox提示框
    Hadoop集群如何动态增加节点
    导入数据库时报错1067 – Invalid default value for ‘字段名‘
    Apache Flink 单节点安装教程和验证
    java 泛型详解和demo代码
    LINUX下创建db2数据库、用户、授权、导入库
  • 原文地址:https://www.cnblogs.com/jpfss/p/9895432.html
Copyright © 2020-2023  润新知