当前位置:   article > 正文

微信H5支付详解(案列) 秒懂_微信h5支付案例

微信h5支付案例
  • 1.了解微信H5支付 流程

1、用户在商户侧完成下单,使用微信支付进行支付

2、由商户后台向微信支付发起下单请求(调用统一下单接口)注:交易类型trade_type=MWEB

3、统一下单接口返回支付相关参数给商户后台,如支付跳转url(参数名“mweb_url”),商户通过mweb_url调起微信支付中间页

4、中间页进行H5权限的校验,安全性检查(此处常见错误请见下文)

5、如支付成功,商户后台会接收到微信侧的异步通知

6、用户在微信支付收银台完成支付或取消支付,返回商户页面(默认为返回支付发起页面)

7、商户在展示页面,引导用户主动发起支付结果的查询

8,9、商户后台判断是否接到收微信侧的支付结果通知,如没有,后台调用我们的订单查询接口确认订单状态

10、展示最终的订单支付结果给用户


 

  • 2maven
  1. <dependency>
  2. <groupId>com.thoughtworks.xstream</groupId>
  3. <artifactId>xstream</artifactId>
  4. <version>1.4.8</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>commons-fileupload</groupId>
  8. <artifactId>commons-fileupload</artifactId>
  9. <version>1.2.2</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>commons-io</groupId>
  13. <artifactId>commons-io</artifactId>
  14. <version>2.0.1</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>commons-codec</groupId>
  18. <artifactId>commons-codec</artifactId>
  19. <version>1.10</version>
  20. </dependency>
  21. <dependency>
  22. <groupId>net.sf.json-lib</groupId>
  23. <artifactId>json-lib</artifactId>
  24. <version>2.4</version>
  25. <classifier>jdk15</classifier>
  26. </dependency>
  27. <dependency>
  28. <groupId>org.jdom</groupId>
  29. <artifactId>jdom</artifactId>
  30. <version>2.0.2</version>
  31. </dependency>
  32. <dependency>
  33. <groupId>org.apache.httpcomponents</groupId>
  34. <artifactId>httpcore</artifactId>
  35. <version>4.4.10</version>
  36. </dependency>
  37. <dependency>
  38. <groupId>org.apache.httpcomponents</groupId>
  39. <artifactId>httpmime</artifactId>
  40. <version>4.5.2</version>
  41. </dependency>
  42. <dependency>
  43. <groupId>commons-httpclient</groupId>
  44. <artifactId>commons-httpclient</artifactId>
  45. <version>3.1</version>
  46. </dependency>
  • 3 controller
  1. //回调地址
  2. String notifyUrl = PropUtil.getString("notifyurl", "", Constant.H5PAY_FILE);
  3. if (notifyUrl.endsWith("/")){
  4. notifyUrl+="h5";
  5. }else{
  6. notifyUrl+="/h5";
  7. }
  8. String APPID = PropUtil.getString("h5payAPPID");//商户号取配置;
  9. String MERID = PropUtil.getString("h5payMERID");//;
  10. String SIGNKEY = "&^$&())^%3124";//;
  11. String h5payurl=PropUtil.getString("h5payurl");
  12. logger.info("APPID="+APPID);
  13. String spbill_create_ip = getIpAddr(request);//生产
  14. // System.out.println("spbill_create_ip="+spbill_create_ip);
  15. logger.info("spbill_create_ip="+spbill_create_ip);
  16. //String spbill_create_ip = "";//测试地址,也就是本地真是ip,用于本地测试用
  17. String scene_info = "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \""+h5payurl+"\",\"wap_name\": \"代理购钻\"}}";//我这里是网页入口,app入口参考文档的安卓和ios写法 授权地址 和购买信息
  18. String tradeType = "MWEB";//H5支付标记
  19. String MD5 = "MD5";//虽然官方文档不是必须参数,但是不送有时候会验签失败
  20. JSONObject result = new JSONObject();
  21. String subject = "代理购钻";//前端上送的支付主题
  22. String total_amount = String.valueOf(orderAmount);//前端上送的支付金额
  23. String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
  24. //金额转化为分为单位 微信支付以分为单位
  25. BigDecimal b1 = new BigDecimal(Double.valueOf(total_amount));
  26. BigDecimal b2 = new BigDecimal(Double.toString(0.01));
  27. logger.info("b1:"+b1.toString());
  28. logger.info("b2:"+b2.toString());
  29. BigDecimal b3= new BigDecimal(b1.multiply(b2).doubleValue()).setScale(0, BigDecimal.ROUND_HALF_UP);
  30. logger.info(b3.toString());
  31. String finalmoney = StringUtil.getMoney(b3.toString());//;
  32. logger.info(finalmoney);
  33. int randomNum = (int) (Math.random() * 1999+5000);
  34. /*String out_trade_no = Util.getSysTime("yyyyMMddHHmmss") + randomNum;*/
  35. //随机数
  36. String nonce_str= MD5Utils.getMessageDigest(String.valueOf(new Random().nextInt(10000)).getBytes());
  37. // String nonce_str = RandomStringUtils.randomAlphabetic(10);
  38. //签名数据
  39. StringBuilder sb = new StringBuilder();
  40. sb.append("appid="+APPID);
  41. sb.append("&body="+subject);
  42. sb.append("&mch_id="+MERID);
  43. sb.append("&nonce_str="+nonce_str);
  44. sb.append("&notify_url="+notifyUrl);
  45. sb.append("&out_trade_no="+out_trade_no);
  46. sb.append("&scene_info="+scene_info);
  47. sb.append("&sign_type="+"MD5");
  48. sb.append("&spbill_create_ip="+spbill_create_ip);
  49. sb.append("&total_fee="+finalmoney);
  50. sb.append("&trade_type="+tradeType);
  51. sb.append("&key="+SIGNKEY);
  52. System.out.println("sb="+sb);
  53. logger.info("sb="+sb);
  54. //签名MD5加密
  55. String sign = MD5Utils.md5Encode(sb.toString()).toUpperCase();
  56. System.out.println("sign="+sign);
  57. logger.info("签名数据:"+sign);
  58. //封装xml报文
  59. String xml="<xml>"+
  60. "<appid>"+ APPID+"</appid>"+
  61. "<mch_id>"+ MERID+"</mch_id>"+
  62. "<nonce_str>"+nonce_str+"</nonce_str>"+
  63. "<sign>"+sign+"</sign>"+
  64. "<body>"+subject+"</body>"+//
  65. "<out_trade_no>"+out_trade_no+"</out_trade_no>"+
  66. "<total_fee>"+finalmoney+"</total_fee>"+//
  67. "<trade_type>"+tradeType+"</trade_type>"+
  68. "<notify_url>"+notifyUrl+"</notify_url>"+
  69. "<sign_type>MD5</sign_type>"+
  70. "<scene_info>"+scene_info+"</scene_info>"+
  71. "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+
  72. "</xml>";
  73. String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信统一下单接口
  74. String mweb_url = "";
  75. Map map = new HashMap();
  76. logger.info("报文:"+xml);
  77. try {
  78. //预下单 获取接口地址
  79. map = WebUtils.getMwebUrl(createOrderURL, xml);
  80. logger.info("请求返回结果:"+map);
  81. String return_code = (String) map.get("return_code");
  82. String return_msg = (String) map.get("return_msg");
  83. if("SUCCESS".equals(return_code) && "OK".equals(return_msg)){
  84. mweb_url = (String) map.get("mweb_url");//调微信支付接口地址
  85. // System.out.println("mweb_url="+mweb_url);
  86. logger.info("create order url:"+mweb_url);
  87. //操作自己的业务逻辑
  88. OutputUtil.output(MessageBuilder.newInstance()
  89. .builderCodeMessage(1000, "OK").builder("body","代理购钻").builder("pay_info",mweb_url).builder("type","微信支付")
  90. .builder("out_trade_no", orderInfo.getOrderId()).builder("total_fee", orderInfo.getOrderAmount())
  91. , request, response, null, false);
  92. return;
  93. }else{
  94. OutputUtil.output(1002, "购钻失败,请稍后再试", request, response, false);
  95. return;
  96. }
  97. } catch (Exception e) {
  98. logger.error("Exception:" + e.getMessage(), e);
  99. }
  • 4工具类
  1. /**
  2. * Project Name:pay-protocol
  3. * File Name:Xml.java
  4. * Package Name:cn.swiftpass.pay.protocol
  5. * Date:2014-8-10下午10:48:21
  6. *
  7. */
  8. package com.sy.util;
  9. import org.dom4j.Document;
  10. import org.dom4j.Element;
  11. import org.dom4j.io.SAXReader;
  12. import org.xml.sax.InputSource;
  13. import javax.servlet.ServletInputStream;
  14. import javax.servlet.http.HttpServletRequest;
  15. import java.io.*;
  16. import java.util.*;
  17. /**
  18. * ClassName:Xml
  19. * Function: XML的工具方法
  20. * Date: 2014-8-10 下午10:48:21
  21. * @author
  22. */
  23. public class XmlUtils {
  24. /** <一句话功能简述>
  25. * <功能详细描述>request转字符串
  26. * @param request
  27. * @return
  28. * @see [类、类#方法、类#成员]
  29. */
  30. public static String parseRequst(HttpServletRequest request){
  31. String body = "";
  32. try {
  33. ServletInputStream inputStream = request.getInputStream();
  34. BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
  35. while(true){
  36. String info = br.readLine();
  37. if(info == null){
  38. break;
  39. }
  40. if(body == null || "".equals(body)){
  41. body = info;
  42. }else{
  43. body += info;
  44. }
  45. }
  46. } catch (UnsupportedEncodingException e) {
  47. e.printStackTrace();
  48. } catch (IOException e) {
  49. e.printStackTrace();
  50. }
  51. return body;
  52. }
  53. public static String parseXML(SortedMap<String, String> parameters) {
  54. StringBuffer sb = new StringBuffer();
  55. sb.append("<xml>");
  56. Set es = parameters.entrySet();
  57. Iterator it = es.iterator();
  58. while (it.hasNext()) {
  59. Map.Entry entry = (Map.Entry)it.next();
  60. String k = (String)entry.getKey();
  61. String v = (String)entry.getValue();
  62. if (null != v && !"".equals(v) && !"appkey".equals(k)) {
  63. sb.append("<" + k + ">" + parameters.get(k) + "</" + k + ">\n");
  64. }
  65. }
  66. sb.append("</xml>");
  67. return sb.toString();
  68. }
  69. /**
  70. * 从request中获得参数Map,并返回可读的Map
  71. *
  72. * @param request
  73. * @return
  74. */
  75. public static SortedMap getParameterMap(HttpServletRequest request) {
  76. // 参数Map
  77. Map properties = request.getParameterMap();
  78. // 返回值Map
  79. SortedMap returnMap = new TreeMap();
  80. Iterator entries = properties.entrySet().iterator();
  81. Map.Entry entry;
  82. String name = "";
  83. String value = "";
  84. while (entries.hasNext()) {
  85. entry = (Map.Entry) entries.next();
  86. name = (String) entry.getKey();
  87. Object valueObj = entry.getValue();
  88. if(null == valueObj){
  89. value = "";
  90. }else if(valueObj instanceof String[]){
  91. String[] values = (String[])valueObj;
  92. for(int i=0;i<values.length;i++){
  93. value = values[i] + ",";
  94. }
  95. value = value.substring(0, value.length()-1);
  96. }else{
  97. value = valueObj.toString();
  98. }
  99. returnMap.put(name, value.trim());
  100. }
  101. return returnMap;
  102. }
  103. /**
  104. * 转XMLmap
  105. * @author
  106. * @param xmlBytes
  107. * @param charset
  108. * @return
  109. * @throws Exception
  110. */
  111. public static Map<String, String> toMap(byte[] xmlBytes,String charset) throws Exception{
  112. SAXReader reader = new SAXReader(false);
  113. InputSource source = new InputSource(new ByteArrayInputStream(xmlBytes));
  114. source.setEncoding(charset);
  115. Document doc = reader.read(source);
  116. Map<String, String> params = XmlUtils.toMap(doc.getRootElement());
  117. return params;
  118. }
  119. /**
  120. * 转MAP
  121. * @author
  122. * @param element
  123. * @return
  124. */
  125. public static Map<String, String> toMap(Element element){
  126. Map<String, String> rest = new HashMap<String, String>();
  127. List<Element> els = element.elements();
  128. for(Element el : els){
  129. rest.put(el.getName().toLowerCase(), el.getTextTrim());
  130. }
  131. return rest;
  132. }
  133. public static String toXml(Map<String, String> params){
  134. StringBuilder buf = new StringBuilder();
  135. List<String> keys = new ArrayList<String>(params.keySet());
  136. Collections.sort(keys);
  137. buf.append("<xml>");
  138. for(String key : keys){
  139. buf.append("<").append(key).append(">");
  140. buf.append("<![CDATA[").append(params.get(key)).append("]]>");
  141. buf.append("</").append(key).append(">\n");
  142. }
  143. buf.append("</xml>");
  144. return buf.toString();
  145. }
  146. }
  1. package com.sy.util;
  2. import com.alibaba.fastjson.JSON;
  3. import com.sy.mainland.util.HttpsUtil;
  4. import com.sy.mainland.util.SHAUtil;
  5. import com.alibaba.fastjson.JSON;
  6. import com.sy.mainland.util.HttpsUtil;
  7. import com.sy.mainland.util.SHAUtil;
  8. import org.apache.commons.httpclient.HttpClient;
  9. import org.apache.commons.httpclient.methods.PostMethod;
  10. import org.apache.commons.httpclient.methods.StringRequestEntity;
  11. import org.slf4j.Logger;
  12. import org.slf4j.LoggerFactory;
  13. import org.springframework.http.RequestEntity;
  14. import java.io.BufferedInputStream;
  15. import java.util.HashMap;
  16. import java.util.LinkedHashMap;
  17. import java.util.Map;
  18. public class WebUtils {
  19. public static Map getMwebUrl(String url,String xmlParam){
  20. String jsonStr = null;
  21. HttpClient httpClient = new HttpClient();
  22. Map map = new HashMap();
  23. try {
  24. PostMethod method = null;
  25. StringRequestEntity reqEntity = new StringRequestEntity(xmlParam,"text/json","UTF-8");
  26. method = new PostMethod(url);
  27. method.setRequestEntity(reqEntity);
  28. method.addRequestHeader("Content-Type","application/json;charset=utf-8");
  29. httpClient.executeMethod(method);
  30. StringBuffer resBodyBuf = new StringBuffer();
  31. byte[] responseBody = new byte[1024];
  32. int readCount = 0;
  33. BufferedInputStream is = new BufferedInputStream(method.getResponseBodyAsStream());
  34. while((readCount = is.read(responseBody,0,responseBody.length))!=-1){
  35. resBodyBuf.append(new String(responseBody,0,readCount,"utf-8"));
  36. }
  37. jsonStr = resBodyBuf.toString();
  38. System.out.println(jsonStr);
  39. // map = XmlUtils.parseXmlToList(jsonStr);
  40. map = XmlUtils.toMap(jsonStr.getBytes(), "utf-8");
  41. } catch (Exception e) {
  42. e.printStackTrace();
  43. }
  44. return map;
  45. }
  46. }
  1. package com.sy.util;
  2. import java.io.UnsupportedEncodingException;
  3. import java.security.MessageDigest;
  4. /**
  5. * 采用MD5加密
  6. *
  7. * @author relax
  8. */
  9. public class MD5Utils {
  10. public static String md5U(String inStr) {
  11. return md5Encode(inStr).toUpperCase();
  12. }
  13. /***
  14. * MD5加密 生成32位md5码
  15. *
  16. * @param 待加密字符串
  17. * @return 返回32位md5码
  18. */
  19. public static String md5Encode(String inStr) {
  20. MessageDigest md5 = null;
  21. try {
  22. md5 = MessageDigest.getInstance("MD5");
  23. } catch (Exception e) {
  24. System.out.println(e.toString());
  25. e.printStackTrace();
  26. return "";
  27. }
  28. byte[] byteArray;
  29. StringBuffer hexValue = new StringBuffer();
  30. try {
  31. byteArray = inStr.getBytes("UTF-8");
  32. byte[] md5Bytes = md5.digest(byteArray);
  33. for (int i = 0; i < md5Bytes.length; i++) {
  34. int val = ((int) md5Bytes[i]) & 0xff;
  35. if (val < 16) {
  36. hexValue.append("0");
  37. }
  38. hexValue.append(Integer.toHexString(val));
  39. }
  40. } catch (UnsupportedEncodingException e) {
  41. e.printStackTrace();
  42. }
  43. return hexValue.toString();
  44. }
  45. public static String md5For16U(String inStr) {
  46. return md5For16(inStr).toUpperCase();
  47. }
  48. public static String md5For16(String inStr) {
  49. MessageDigest md5 = null;
  50. try {
  51. md5 = MessageDigest.getInstance("MD5");
  52. } catch (Exception e) {
  53. System.out.println(e.toString());
  54. e.printStackTrace();
  55. return "";
  56. }
  57. byte[] byteArray;
  58. StringBuffer hexValue = new StringBuffer();
  59. try {
  60. byteArray = inStr.getBytes("UTF-8");
  61. byte[] md5Bytes = md5.digest(byteArray);
  62. for (int i = 0; i < md5Bytes.length; i++) {
  63. int val = ((int) md5Bytes[i]) & 0xff;
  64. if (val < 16) {
  65. hexValue.append("0");
  66. }
  67. hexValue.append(Integer.toHexString(val));
  68. }
  69. } catch (UnsupportedEncodingException e) {
  70. e.printStackTrace();
  71. }
  72. return hexValue.toString().substring(8, 24);
  73. }
  74. /**
  75. * 测试主函数
  76. *
  77. * @param args
  78. * @throws Exception
  79. */
  80. public static void main(String args[]) throws Exception {
  81. String str = new String("amigoxiexiexingxing");
  82. System.out.println("原始:" + str);
  83. System.out.println("MD5后:" + md5Encode(str));
  84. }
  85. public final static String getMessageDigest(byte[] buffer) {
  86. char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
  87. try {
  88. MessageDigest mdTemp = MessageDigest.getInstance("MD5");
  89. mdTemp.update(buffer);
  90. byte[] md = mdTemp.digest();
  91. int j = md.length;
  92. char str[] = new char[j * 2];
  93. int k = 0;
  94. for (int i = 0; i < j; i++) {
  95. byte byte0 = md[i];
  96. str[k++] = hexDigits[byte0 >>> 4 & 0xf];
  97. str[k++] = hexDigits[byte0 & 0xf];
  98. }
  99. return new String(str);
  100. } catch (Exception e) {
  101. return null;
  102. }
  103. }
  104. }
  1. /**
  2. * 元转换成分
  3. * @param money
  4. * @return
  5. */
  6. public static String getMoney(String amount) {
  7. if(amount==null){
  8. return "";
  9. }
  10. // 金额转化为分为单位
  11. String currency = amount.replaceAll("\\$|\\¥|\\,", ""); //处理包含, ¥ 或者$的金额
  12. int index = currency.indexOf(".");
  13. int length = currency.length();
  14. Long amLong = 0l;
  15. if(index == -1){
  16. amLong = Long.valueOf(currency+"00");
  17. }else if(length - index >= 3){
  18. amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));
  19. }else if(length - index == 2){
  20. amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);
  21. }else{
  22. amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");
  23. }
  24. return amLong.toString();
  25. }
  • 5 回调
  1. @RequestMapping(value = "/notify/h5")
  2. public void weixinPayNotify(HttpServletRequest req, HttpServletResponse resp) throws Exception {
  3. String respString = "fail";
  4. try {
  5. BufferedReader reader = req.getReader();
  6. String line = "";
  7. Map map = new HashMap();
  8. String xml = "<xml><return_code><![CDATA[FAIL]]></xml>";;
  9. JSONObject dataInfo = new JSONObject();
  10. StringBuffer inputString = new StringBuffer();
  11. while ((line = reader.readLine()) != null) {
  12. inputString.append(line);
  13. }
  14. req.getReader().close();
  15. // System.out.println("----接收到的报文---"+inputString.toString());
  16. logger.info("----接收到的报文---"+inputString.toString());
  17. if(inputString.toString().length()>0){
  18. // map = XmlUtils.parseXmlToList(inputString.toString());
  19. map = XmlUtils.toMap(inputString.toString().getBytes(), "utf-8");
  20. }else{
  21. System.out.println("接受微信报文为空");
  22. }
  23. // System.out.println("map="+map);
  24. logger.info("map="+map);
  25. if(map!=null && "SUCCESS".equals(map.get("result_code"))){
  26. //成功的业务。。。
  27. xml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
  28. }
  29. } catch (Exception e) {
  30. logger.error("Exception:" + e.getMessage(), e);
  31. }finally {
  32. resp.getWriter().write(respString);
  33. resp.getWriter().flush();
  34. resp.getWriter().close();
  35. }
  36. }

注:伸手党仔细看一下

 支付常见错误

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/132124
推荐阅读
相关标签
  

闽ICP备14008679号