JAVA实现的微信扫描二维码支付

来源:互联网 发布:查看目录权限 linux 编辑:程序博客网 时间:2024/05/16 05:53

吐槽一下

原文地址:http://blog.52itstyle.com/archives/180/

支付项目采用springMvc+Dubbo架构实现,只对外提供接口。

话说,为什么微信支付比支付宝来的晚了那么一点,一句话,那一阵挺忙的,然后就没有时间整理,最近做完支付宝支付,顺便也把微信支付的也整理一下。

这里再吐槽一下,微信支付的DEMO基本为零,很多代码都是从网上查找的(也可能我么有仔细找API)。

前期酝酿准备

扫码支付,目前来说个人是不可以申请的,包括现在支付宝的即时到帐个人相关业务也取消了。所以这里必须有一个微信支付商户平台,具体怎么申请的,我也不清楚,只是拿来用的。

商户平台是要配合绑定微信公众账号使用的,具体操作申请下来已经绑定了,这里你也只管用就是了。

什么是扫码支付?

场景介绍

用户扫描商户展示在各种场景的二维码进行支付。

步骤1:商户根据微信支付的规则,为不同商品生成不同的二维码(如图6.1),展示在各种场景,用于用户扫描购买。

步骤2:用户使用微信“扫一扫”(如图6.2)扫描二维码后,获取商品支付信息,引导用户完成支付(如图6.3)。
chapter6_1_1.png
chapter6_1_2.jpgchapter6_1_3.jpg
支付二维码
图6.1 支付二维码
打开微信扫一扫二维码
图6.2 打开微信扫一扫二维码
确认支付页面
图6.3 确认支付页面

步骤(3):用户确认支付,输入支付密码(如图6.4)。

步骤(4):支付完成后会提示用户支付成功(如图6.5),商户后台得到支付成功的通知,然后进行发货处理。

用户确认支付,输入密码
图6.4 用户确认支付,输入密码
支付成功提示
图6.5 支付成功提示
chapter6_1_4.jpgchapter6_1_5.jpg

如何集成到项目中去?

ConfigUtil参数配置:

  1. import java.util.Map;
  2. import java.util.ResourceBundle;
  3. import java.util.SortedMap;
  4. import java.util.TreeMap;
  5. /**
  6. * 相关配置参数
  7. * 创建者 张志朋
  8. * 创建时间 2016年9月28日
  9. *
  10. */
  11. public class ConfigUtil {
  12. /**
  13. * 服务号相关信息
  14. */
  15. public final static String APP_ID = "2016";//服务号的应用ID
  16. public final static String APP_SECRET = "2016";//服务号的应用密钥
  17. public final static String TOKEN = "weixinCourse";//服务号的配置token
  18. public final static String MCH_ID = "2016";//商户号
  19. public final static String API_KEY = "2016";//API密钥
  20. public final static String SIGN_TYPE = "MD5";//签名加密方式
  21. public final static String CERT_PATH = "apiclient_cert.p12";//微信支付证书存放路径地址
  22. static ResourceBundle resource = ResourceBundle.getBundle("config");
  23. //微信支付统一接口的回调action
  24. public final static String NOTIFY_URL = resource.getString("WEIXIN_NOTIFY_URL");
  25. /**
  26. * 微信基础接口地址
  27. */
  28. //获取token接口(GET)
  29. public final static String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
  30. //oauth2授权接口(GET)
  31. public final static String OAUTH2_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
  32. //刷新access_token接口(GET)
  33. public final static String REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN";
  34. // 菜单创建接口(POST)
  35. public final static String MENU_CREATE_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
  36. // 菜单查询(GET)
  37. public final static String MENU_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN";
  38. // 菜单删除(GET)
  39. public final static String MENU_DELETE_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";
  40. /**
  41. * 微信支付接口地址
  42. */
  43. //微信支付统一接口(POST)
  44. public final static String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
  45. //微信退款接口(POST)
  46. public final static String REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";
  47. //订单查询接口(POST)
  48. public final static String CHECK_ORDER_URL = "https://api.mch.weixin.qq.com/pay/orderquery";
  49. //关闭订单接口(POST)
  50. public final static String CLOSE_ORDER_URL = "https://api.mch.weixin.qq.com/pay/closeorder";
  51. //退款查询接口(POST)
  52. public final static String CHECK_REFUND_URL = "https://api.mch.weixin.qq.com/pay/refundquery";
  53. //对账单接口(POST)
  54. public final static String DOWNLOAD_BILL_URL = "https://api.mch.weixin.qq.com/pay/downloadbill";
  55. //短链接转换接口(POST)
  56. public final static String SHORT_URL = "https://api.mch.weixin.qq.com/tools/shorturl";
  57. //接口调用上报接口(POST)
  58. public final static String REPORT_URL = "https://api.mch.weixin.qq.com/payitil/report";
  59. public static void commonParams(SortedMap<Object, Object> packageParams){
  60. // 账号信息
  61. String appid = ConfigUtil.APP_ID; // appid
  62. String mch_id = ConfigUtil.MCH_ID; // 商业号
  63. // 生成随机字符串
  64. String currTime = PayCommonUtil.getCurrTime();
  65. String strTime = currTime.substring(8, currTime.length());
  66. String strRandom = PayCommonUtil.buildRandom(4) + "";
  67. String nonce_str = strTime + strRandom;
  68. packageParams.put("appid", appid);// 公众账号ID
  69. packageParams.put("mch_id", mch_id);// 商户号
  70. packageParams.put("nonce_str", nonce_str);// 随机字符串
  71. }
  72. /**
  73. * 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX),减小二维码数据量,提升扫描速度和精确度。
  74. * @Author 张志朋
  75. * @param urlCode void
  76. * @Date 2016年10月26日
  77. * 更新日志
  78. * 2016年10月26日 张志朋 首次创建
  79. *
  80. */
  81. @SuppressWarnings("rawtypes")
  82. public static void shorturl(String urlCode){
  83. try {
  84. String key = ConfigUtil.API_KEY; // key
  85. SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
  86. ConfigUtil.commonParams(packageParams);
  87. packageParams.put("long_url", urlCode);// URL链接
  88. String sign = PayCommonUtil.createSign("UTF-8", packageParams, key);
  89. packageParams.put("sign", sign);// 签名
  90. String requestXML = PayCommonUtil.getRequestXml(packageParams);
  91. String resXml = HttpUtil.postData(ConfigUtil.SHORT_URL, requestXML);
  92. Map map = XMLUtil.doXMLParse(resXml);
  93. String returnCode = (String) map.get("return_code");
  94. if("SUCCESS".equals(returnCode)){
  95. String resultCode = (String) map.get("return_code");
  96. if("SUCCESS".equals(resultCode)){
  97. urlCode = (String) map.get("short_url");
  98. }
  99. }
  100. } catch (Exception e) {
  101. e.printStackTrace();
  102. }
  103. }

参数必填项 APP_ID 和APP_SECRET 是从微信公众号里面获取的,而MCH_ID和API_KEY是从商户平台获取的。CERT_PATH 证书可选,但是如果做退款接口必须要使用证书。NOTIFY_URL 为回调地址,自定义路径,但是一定要微信平台可以调用到你的url。

如何生成二维码订单?

API文档地址

文档有详细的参数说明,具体生成需要xml解析,这里就不放了,好多的说,有需要的可以留言。

支付回调:

  1. /**
  2. * 二维码支付
  3. * 创建者 张志朋
  4. * 创建时间 2016年10月31日
  5. *
  6. */
  7. @Controller
  8. @RequestMapping(value = "weixin")
  9. public class WeixinPayController {
  10. @Autowired
  11. private IWeixinPayService weixinpayBack;
  12. /**
  13. * 微信支付回调
  14. * @Author 张志朋
  15. * @param request
  16. * @param response
  17. * @throws Exception void
  18. * @Date 2016年9月28日
  19. * 更新日志
  20. * 2016年9月28日 张志朋 首次创建
  21. *
  22. */
  23. @SuppressWarnings({ "unchecked", "rawtypes" })
  24. @RequestMapping(value = "pay")
  25. public void weixin_notify(HttpServletRequest request, HttpServletResponse response) throws Exception {
  26. LogUtil.info("支付成功回调");
  27. // 读取参数
  28. InputStream inputStream = request.getInputStream();
  29. StringBuffer sb = new StringBuffer();
  30. String s;
  31. BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
  32. while ((s = in.readLine()) != null) {
  33. sb.append(s);
  34. }
  35. in.close();
  36. inputStream.close();
  37. // 解析xml成map
  38. Map<String, String> m = new HashMap<String, String>();
  39. m = XMLUtil.doXMLParse(sb.toString());
  40. // 过滤空 设置 TreeMap
  41. SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
  42. Iterator it = m.keySet().iterator();
  43. while (it.hasNext()) {
  44. String parameter = (String) it.next();
  45. String parameterValue = m.get(parameter);
  46. String v = "";
  47. if (null != parameterValue) {
  48. v = parameterValue.trim();
  49. }
  50. packageParams.put(parameter, v);
  51. }
  52. // 账号信息
  53. String key = ConfigUtil.API_KEY; // key
  54. // 判断签名是否正确
  55. if (PayCommonUtil.isTenpaySign("UTF-8", packageParams, key)) {
  56. // ------------------------------
  57. // 处理业务开始
  58. // ------------------------------
  59. String resXml = "";
  60. if ("SUCCESS".equals((String) packageParams.get("result_code"))) {
  61. // 这里是支付成功
  62. String orderNo = (String) packageParams.get("out_trade_no");
  63. String attach = (String) packageParams.get("attach");
  64. //回调K12
  65. LogUtil.info(attach+"(订单号:"+orderNo+"付款成功)");
  66. // 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
  67. resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
  68. weixinpayBack.updateAccOrder(orderNo);
  69. } else {
  70. LogUtil.info("支付失败,错误信息:" + packageParams.get("err_code"));
  71. resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
  72. }
  73. // ------------------------------
  74. // 处理业务完毕
  75. // ------------------------------
  76. BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
  77. out.write(resXml.getBytes());
  78. out.flush();
  79. out.close();
  80. } else {
  81. LogUtil.info("通知签名验证失败");
  82. }
  83. }
  84. }

大体就这个样子,后续的可能就是安全优化了。涉及到钱可不是小问题。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 晚上衣服干不了怎么办 3dmax视图混乱怎么办 钉枪能打进肉里怎么办 公司迟发工资怎么办 打枪后一直耳鸣怎么办 打枪震的耳鸣怎么办 尚方宝剑弄丢了怎么办 九五出款被黑18w怎么办 很容易感动伤感哭怎么办 为什么安卓版ps打不开怎么办 遇见职业打假人怎么办 打假投诉极限次怎么办 导师无故留学生要怎么办 孩子24了不争气怎么办 退休工资卡遗失怎么办大同市 天津体育惠民卡怎么办 高跟鞋走路太响怎么办 高跟鞋太响怎么办妙招 穿高跟鞋想开车怎么办 脚瘦穿高跟鞋容易掉怎么办 dq11时装卖了怎么办 廉洁教育手抄报怎么办 做美发口才不好怎么办 月嫂怎么办澳大利亚签证 高一学生叛逆怎么办 和异性说话紧张怎么办 幼儿教师模拟讲课紧张怎么办 静不下心来怎么办 失眠焦虑到极点怎么办 老师罚学生买东西怎么办 大学每晚查寝怎么办 教育机构会计账怎么办 车陂扣12分的话怎么办 公选课挂科怎么办 颈椎疼带头疼怎么办 本科出身不好该怎么办 科研经历不丰富怎么办 拍电影需要一些公共场所怎么办 录屏没有声音怎么办 超星课程里阅读怎么办 微信自动冻结怎么办