发布时间:2018-10-05
 
技术:springboot+maven
 

概述

java微信小程序demo支付只需配置支付一下参数即可运行

详细

一、前言

(1)适合人群

1,java服务端开发人员

2,初级人员开发人员

3,了解spring springboot+maven

3,了解小程序开发跟前端人员接口对接

(2) 你需要准备什么?

1,积极主动学习

2,微信开发基本流程

3,java后端几大框架掌握如(spring springboot maven mybatis)

二、前期准备工作

软件环境:eclipse

官方下载:https://www.eclipse.org/downloads/

1丶基本需求

1,实现商品支付功能

2,项目目录结构

三、实现步骤

1.在小程序中获取用户的登录信息,成功后可以获取到用户的code值

2.在用户自己的服务端请求微信获取用户openid接口,成功后可以获取用户的openid值

微信官方api地址:点击打开链接

3.在用户自己的服务器上面请求微信的统一下单接口,下单成功后可以获取prepay_id值

微信官方api地址:点击打开链接

4.在微信小程序中支付订单,最终实现微信的支付功能

微信官方api地址:点击打开链接

1,下面我们就开始详细的介绍一下微信支付的整个流程:

首先是获取用户的信息,也就是小程序中的登录接口:

  1. //app.js
  2. App({
  3. onLaunch: function() {
  4. wx.login({
  5. success: function(res) {
  6. if (res.code) {
  7. //发起网络请求
  8. wx.request({
  9. url: 'https://test.com/onLogin',
  10. data: {
  11. code: res.code
  12. }
  13. })
  14. } else {
  15. console.log('获取用户登录态失败!' + res.errMsg)
  16. }
  17. }
  18. });
  19. }
  20. })

2,contrller层实现登陆方法方法

  1. /**
  2. * @Description: 本示例仅供参考,请根据自己的使用情景进行修改
  3. * @Date: 2018/7/17
  4. * @Author: wcf
  5. */
  6. @RequestMapping("/weixin")
  7. @RestController
  8. public class WeixinController extends WeixinSupport{
  9.  
  10. private Logger logger = LoggerFactory.getLogger(getClass());
  11.  
  12. private static final String appid = ""; //微信小程序appid
  13. private static final String secret = ""; //微信小程序密钥
  14. private static final String grant_type = "";
  15.  
  16. /**
  17. * 小程序后台登录,向微信平台发送获取access_token请求,并返回openId
  18. *
  19. * @param code
  20. * @return openid
  21. * @throws WeixinException
  22. * @throws IOException
  23. * @since Weixin4J 1.0.0
  24. */
  25. @RequestMapping("login")
  26. public Map<String, Object> login(String code, HttpServletRequest request) throws WeixinException, IOException {
  27. if (code == null || code.equals("")) {
  28. throw new WeixinException("invalid null, code is null.");
  29. }
  30.  
  31. Map<String, Object> ret = new HashMap<String, Object>();
  32. //拼接参数
  33. String param = "?grant_type=" + grant_type + "&appid=" + appid + "&secret=" + secret + "&js_code=" + code;
  34.  
  35. //创建请求对象
  36. HttpsClient http = new HttpsClient();
  37. //调用获取access_token接口
  38. Response res = http.get("https://api.weixin.qq.com/sns/jscode2session" + param);
  39. //根据请求结果判定,是否验证成功
  40. JSONObject jsonObj = res.asJSONObject();
  41. if (jsonObj != null) {
  42. Object errcode = jsonObj.get("errcode");
  43. if (errcode != null) {
  44. //返回异常信息
  45. throw new WeixinException(getCause(Integer.parseInt(errcode.toString())));
  46. }
  47.  
  48. ObjectMapper mapper = new ObjectMapper();
  49. OAuthJsToken oauthJsToken = mapper.readValue(jsonObj.toJSONString(),OAuthJsToken.class);
  50.  
  51. logger.info("openid=" + oauthJsToken.getOpenid());
  52. ret.put("openid", oauthJsToken.getOpenid());
  53. }
  54. return ret;
  55. }

3、发起微信支付请求

  1. /**
  2. * @Description: 发起微信支付
  3. * @param openid
  4. * @param request
  5. * @author: wcf
  6. * @date: 2018年7月17日
  7. */
  8. @RequestMapping("wxPay")
  9. public Json wxPay(String openid, HttpServletRequest request){
  10. Json json = new Json();
  11. try{
  12. //生成的随机字符串
  13. String nonce_str = StringUtils.getRandomStringByLength(32);
  14. //商品名称
  15. String body = "测试商品名称";
  16. //获取本机的ip地址
  17. String spbill_create_ip = IpUtils.getIpAddr(request);
  18.  
  19. String orderNo = "123456788";
  20. String money = "1";//支付金额,单位:分,这边需要转成字符串类型,否则后面的签名会失败
  21.  
  22. Map<String, String> packageParams = new HashMap<String, String>();
  23. packageParams.put("appid", WxPayConfig.appid);
  24. packageParams.put("mch_id", WxPayConfig.mch_id);
  25. packageParams.put("nonce_str", nonce_str);
  26. packageParams.put("body", body);
  27. packageParams.put("out_trade_no", orderNo);//商户订单号
  28. packageParams.put("total_fee", money);//支付金额,这边需要转成字符串类型,否则后面的签名会失败
  29. packageParams.put("spbill_create_ip", spbill_create_ip);
  30. packageParams.put("notify_url", WxPayConfig.notify_url);
  31. packageParams.put("trade_type", WxPayConfig.TRADETYPE);
  32. packageParams.put("openid", openid);
  33.  
  34. // 除去数组中的空值和签名参数
  35. packageParams = PayUtil.paraFilter(packageParams);
  36. String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
  37.  
  38. //MD5运算生成签名,这里是第一次签名,用于调用统一下单接口
  39. String mysign = PayUtil.sign(prestr, WxPayConfig.key, "utf-8").toUpperCase();
  40. logger.info("=======================第一次签名:" + mysign + "=====================");
  41.  
  42. //拼接统一下单接口使用的xml数据,要将上一步生成的签名一起拼接进去
  43. String xml = "<xml>" + "<appid>" + WxPayConfig.appid + "</appid>"
  44. + "<body><![CDATA[" + body + "]]></body>"
  45. + "<mch_id>" + WxPayConfig.mch_id + "</mch_id>"
  46. + "<nonce_str>" + nonce_str + "</nonce_str>"
  47. + "<notify_url>" + WxPayConfig.notify_url + "</notify_url>"
  48. + "<openid>" + openid + "</openid>"
  49. + "<out_trade_no>" + orderNo + "</out_trade_no>"
  50. + "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>"
  51. + "<total_fee>" + money + "</total_fee>"
  52. + "<trade_type>" + WxPayConfig.TRADETYPE + "</trade_type>"
  53. + "<sign>" + mysign + "</sign>"
  54. + "</xml>";
  55.  
  56. System.out.println("调试模式_统一下单接口 请求XML数据:" + xml);
  57.  
  58. //调用统一下单接口,并接受返回的结果
  59. String result = PayUtil.httpRequest(WxPayConfig.pay_url, "POST", xml);
  60.  
  61. System.out.println("调试模式_统一下单接口 返回XML数据:" + result);
  62.  
  63. // 将解析结果存储在HashMap中
  64. Map map = PayUtil.doXMLParse(result);
  65.  
  66. String return_code = (String) map.get("return_code");//返回状态码
  67.  
  68. //返回给移动端需要的参数
  69. Map<String, Object> response = new HashMap<String, Object>();
  70. if(return_code == "SUCCESS" || return_code.equals(return_code)){
  71. // 业务结果
  72. String prepay_id = (String) map.get("prepay_id");//返回的预付单信息
  73. response.put("nonceStr", nonce_str);
  74. response.put("package", "prepay_id=" + prepay_id);
  75. Long timeStamp = System.currentTimeMillis() / 1000;
  76. response.put("timeStamp", timeStamp + "");//这边要将返回的时间戳转化成字符串,不然小程序端调用wx.requestPayment方法会报签名错误
  77.  
  78. String stringSignTemp = "appId=" + WxPayConfig.appid + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id+ "&signType=" + WxPayConfig.SIGNTYPE + "&timeStamp=" + timeStamp;
  79. //再次签名,这个签名用于小程序端调用wx.requesetPayment方法
  80. String paySign = PayUtil.sign(stringSignTemp, WxPayConfig.key, "utf-8").toUpperCase();
  81. logger.info("=======================第二次签名:" + paySign + "=====================");
  82.  
  83. response.put("paySign", paySign);
  84. //更新订单信息
  85. //业务逻辑代码
  86. }
  87. response.put("appid", WxPayConfig.appid);
  88.  
  89. json.setSuccess(true);
  90. json.setData(response);
  91. }catch(Exception e){
  92. e.printStackTrace();
  93. json.setSuccess(false);
  94. json.setMsg("发起失败");
  95. }
  96. return json;
  97. }

4、微信WxPayConfig配置

  1. /**
  1. * @Description:
  2. * @Date: 2018/7/17
  3. * @Author: wcf
  4. */
  5. public class WxPayConfig {
  6. //小程序appid
  7. public static final String appid = "";
  8. //微信支付的商户id
  9. public static final String mch_id = "";
  10. //微信支付的商户密钥
  11. public static final String key = "";
  12. //支付成功后的服务器回调url
  13. public static final String notify_url = "";
  14. //签名方式
  15. public static final String SIGNTYPE = "MD5";
  16. //交易类型
  17. public static final String TRADETYPE = "JSAPI";
  18. //微信统一下单接口地址
  19. public static final String pay_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
  20. }

5、下面是IpUtils工具类

  1. /**
  1. * @Description:
  2. * @Date: 2018/7/17
  3. * @Author: wcf
  4. */
  5. public class IpUtils {
  6. /**
  7. * IpUtils工具类方法
  8. * 获取真实的ip地址
  9. * @param request
  10. * @return
  11. */
  12. public static String getIpAddr(HttpServletRequest request) {
  13. String ip = request.getHeader("X-Forwarded-For");
  14. if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){
  15. //多次反向代理后会有多个ip值,第一个ip才是真实ip
  16. int index = ip.indexOf(",");
  17. if(index != -1){
  18. return ip.substring(0,index);
  19. }else{
  20. return ip;
  21. }
  22. }
  23. ip = request.getHeader("X-Real-IP");
  24. if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){
  25. return ip;
  26. }
  27. return request.getRemoteAddr();
  28. }
  29. }

6、StringUtils工具类等

  1. /**
  1. * @Description:
  2. * @Date: 2018/7/17
  3. * @Author: wcf
  4. */
  5. public class StringUtils extends org.apache.commons.lang3.StringUtils{
  6. /**
  7. * StringUtils工具类方法
  8. * 获取一定长度的随机字符串,范围0-9,a-z
  9. * @param length:指定字符串长度
  10. * @return 一定长度的随机字符串
  11. */
  12. public static String getRandomStringByLength(int length) {
  13. String base = "abcdefghijklmnopqrstuvwxyz0123456789";
  14. Random random = new Random();
  15. StringBuffer sb = new StringBuffer();
  16. for (int i = 0; i < length; i++) {
  17. int number = random.nextInt(base.length());
  18. sb.append(base.charAt(number));
  19. }
  20. return sb.toString();
  21. }
  22. }

7、微信请求回调contrller

  1. /**
  1. * @Description:微信支付
  2. * @return
  3. * @author dzg
  4. * @throws Exception
  5. * @throws WeixinException
  6. * @date 2018717
  7. */
  8. @RequestMapping(value="/wxNotify")
  9. public void wxNotify(HttpServletRequest request,HttpServletResponse response) throws Exception{
  10. BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream)request.getInputStream()));
  11. String line = null;
  12. StringBuilder sb = new StringBuilder();
  13. while((line = br.readLine())!=null){
  14. sb.append(line);
  15. }
  16. br.close();
  17. //sb为微信返回的xml
  18. String notityXml = sb.toString();
  19. String resXml = "";
  20. System.out.println("接收到的报文:" + notityXml);
  21.  
  22. Map map = PayUtil.doXMLParse(notityXml);
  23.  
  24. String returnCode = (String) map.get("return_code");
  25. if("SUCCESS".equals(returnCode)){
  26. //验证签名是否正确
  27. if(PayUtil.verify(PayUtil.createLinkString(map), (String)map.get("sign"), WxPayConfig.key, "utf-8")){
  28. /**此处添加自己的业务逻辑代码start**/
  29.  
  30. /**此处添加自己的业务逻辑代码end**/
  31.  
  32. //通知微信服务器已经支付成功
  33. resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
  34. + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
  35. }
  36. }else{
  37. resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
  38. + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
  39. }
  40. System.out.println(resXml);
  41. System.out.println("微信支付回调数据结束");
  42.  
  43. BufferedOutputStream out = new BufferedOutputStream(
  44. response.getOutputStream());
  45. out.write(resXml.getBytes());
  46. out.flush();
  47. out.close();
  48. }
  1. 7,请求的接口是 注意code是从微信小程序传的codecode是我随意的code必须从小程序那边获取才能调起微信支付
  2. http://localhost:8080/weixin/wxPay?code=code

8,成功后显示如图

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

java服务端微信小程序支付的更多相关文章

  1. Java实现微信小程序支付(准备)

    Java语言开发微信小程序支付功能: 1.通过https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1路径到官方下载Java的支付SD ...

  2. 微信小程序支付源码,后台服务端代码

    作者:尹华南,来自原文地址 微信小程序支付绕坑指南 步骤 A:小程序向服务端发送商品详情.金额.openid B:服务端向微信统一下单 C:服务器收到返回信息二次签名发回给小程序 D:小程序发起支付 ...

  3. Java实现微信小程序支付(完整版)

    在开发微信小程序支付的功能前,我们先熟悉下微信小程序支付的业务流程图: 不熟悉流程的建议还是仔细阅读微信官方的开发者文档. 一,准备工作 事先需要申请企业版小程序,并开通“微信支付”(即商户功能).并 ...

  4. Java 后端微信小程序支付demo (网上说的坑里面基本上都有)

    Java 后端微信小程序支付 一.遇到的问题 1. 商户号该产品权限未开通,请前往商户平台>产品中心检查后重试 2.签名错误 3.已经调起微信统一下单接口,可以拿到预支付ID,但是前端支付的时候 ...

  5. 【原创】微信小程序支付java后台案例(公众号支付同适用)(签名错误问题)

    前言 1.微信小程序支付官方接口文档:[点击查看微信开放平台api开发文档]2.遇到的坑:预支付统一下单签名结果返回[签名错误]失败,建议用官方[签名验证工具]检查签名是否存在问题.3.遇到的坑:签名 ...

  6. php对接微信小程序支付

    前言:这里我就假装你已经注册了微信小程序,并且基本的配置都已经好了.注: 个人注册小程序不支持微信支付,所以我还是假装你是企业或者个体工商户的微信小程序,其他的商户号注册,二者绑定,授权,支付开通,就 ...

  7. .Net后台实现微信小程序支付

    最近一直再研究微信支付和支付宝支付,官方支付文档中一直在讲与第三方支付打交道的原理,却没有介绍我们自己项目中的APP与后台该怎么交互(哈哈,人家也没必要介绍这一块).拜读了官方文档和前辈们的佳作,自己 ...

  8. 微信小程序支付(企业支付给用户零钱)

    内容摘要:本案例客户端支付方式为微信小程序支付(JSAPI).商户运营一段时间后,在微信商户平台开通企业支付服务后,即可调用微信支付提供的企业付款接口将佣金等金额通过微信零钱返现给C端用户零钱. 服务 ...

  9. 微信小程序支付及退款流程详解

    微信小程序的支付和退款流程 近期在做微信小程序时,涉及到了小程序的支付和退款流程,所以也大概的将这方面的东西看了一个遍,就在这篇博客里总结一下. 首先说明一下,微信小程序支付的主要逻辑集中在后端,前端 ...

随机推荐

  1. iOS:麦克风权限检测和获取

    一.检测 该方法是用来判断麦克风是否进行过授权,如果授权过就直接进行需要的功能操作:如果没有进行授权,那么就要获取授权. AVAuthorizationStatus authStatus = [AVC ...

  2. JDBC 查询的三大参数

    本文转载至 http://blog.csdn.net/turkeyzhou/article/details/5115228 DBC1.0 .JDBC2.0 .JDBC3.0 中分别用以下方法创建Sta ...

  3. BERT的开源实现的使用

    参考这篇文章: 小数据福音!BERT在极小数据下带来显著提升的开源实现 https://mp.weixin.qq.com/s?__biz=MzIwMTc4ODE0Mw==&mid=224749 ...

  4. go语言之进阶篇文件常用操作接口介绍和使用

    一.文件常用操作接口介绍 1.创建文件 法1: 推荐用法 func Create(name string) (file *File, err Error) 根据提供的文件名创建新的文件,返回一个文件对 ...

  5. [leetcode]Pascal's Triangle II @ Python

    原题地址:https://oj.leetcode.com/problems/pascals-triangle-ii/ 题意: Given an index k, return the kth row ...

  6. 【google面试题】求1到n的正数中1出现的次数的两种思路及其复杂度分析

    问题描写叙述: 输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数.比如输入12,从1到12这些整数中包括1 的数字有1.10.11和12.1一共出现了5次. 这是一道广为流传的googl ...

  7. Fixing the JavaScript typeof operator

    https://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/javascript 类 ...

  8. Logistic 回归梯度上升优化函数

    In [183]:           def loadDataSet(): dataMat = [] labelMat = [] fr = open('testSet.txt') for line ...

  9. Android 演示 ViewPager

    本文内容 环境 项目结构 演示 1:PagerTitleStrip 演示 2:PagerTabStrip 演示 3:ViewPager 和动态 Fragment 下载 Demo 环境 Windows ...

  10. android中使用toolbar

    系统默认使用的是ActionBar,就是界面中的标题栏,但是由于ActionBar设计的原因,被限定只能位于活动的顶部,从而不能实现Material Design效果,所以官方建议使用Toolbar替 ...