微信支付类型

微信支付实际上有很多种不同的类型,具体要使用哪一种就需要根据不同的应用场景来选择,官方给出的参考例子:
刷卡支付:用户打开微信钱包的刷卡的界面,商户扫码后提交完成支付。
公众号支付:用户在微信内进入商家H5页面,页面内调用JSSDK完成支付
扫码支付:用户打开"微信扫一扫“,扫描商户的二维码后完成支付
APP支付:商户APP中集成微信SDK,用户点击后跳转到微信内完成支付
H5支付:用户在微信以外的手机浏览器请求微信支付的场景唤起微信支付
小程序支付:用户在微信小程序中使用微信支付的场景
本篇文章实现的是公众号支付,会使用到网页授权及微信JS-SDK相关知识,但不再详细介绍
建议大家先阅读以下文章了解相关内容:
网页授权:https://www.jianshu.com/p/94b0e53cccc3
微信JS-SDK:https://www.jianshu.com/p/b3c4450f845e
实现效果如下动图:


公众号支付相关配置

本篇文章中实现的是公众号支付,实现条件如下:
1.需要一个已经进行微信认证的公众号


2.该公众号需要开通微信支付功能

3.到微信商户平台https://pay.weixin.qq.com 注册一个商户账号,并关联你的公众号,如果需要实现小程序支付的,需要关联小程序。

4.拥有一个正式的应用服务器,并且注册域名
微信支付涉及的私密数据比较多,不允许使用natapp,花生壳之类的内网穿透工具实现,需要有正式的服务器环境,并且要注册域名,不能使用IP。
比如:http://www.baidu.com

5.相关配置
5.1 配置支付授权目录,登录商户平台——>产品中心——>开发配置
图中配置的例子,代表在项目根路径下,以及web目录下的页面都有支付权限,如果不在该路径的页面,则无法调用支付功能。
若页面地址为:http://mywexx.xxxx.com/web/pay.html
则需要配置为:http://mywexx.xxxx.com/web/

5.2  设置API密钥,登录商户平台——>账户中心——>API安全——>API密钥
该密钥在后面的代码中计算支付签名的时候需要使用到。

5.3 配置JS接口安全域名与网页授权域名,登录公众平台——>公众号设置——>功能设置
配置网页授权域名:主要用于获取用户的openId,需要识别这是哪个人。
若对openID不了解的同学可先参考微信公众号开发文档:https://mp.weixin.qq.com/wiki
配置JS接口安全域名:要让我们的页面中弹出输入密码的窗口,需要使用微信提供的JS-SDK工具,如果不配置JS接口安全域名,你的页面无法使用JS-SDK。


公众号支付实现流程

大致流程参考官方提供的时序图:


流程有很多,不一一演示,我们选取核心部分来实现。
1.提供商城主页,用户进入后通过网页授权获取openid

如果对网页授权不熟悉的同学先参考这篇文章:
https://www.jianshu.com/p/94b0e53cccc3
访问主页的地址:http://www.wolfcode.cn/index.do
当用户第一次打开主页,默认没有code参数,此时会先重定向到获取授权的地址
(如果只需要获取openid,可以使用scope为snsapi_base静默授权的方式)
经过授权地址再重定向到我们的index.do时,会带上code参数,此时即可通过接口获取用户的openid
[AppleScript] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
[/size][/align][align=left][size=17px]@Controller[/size][/align][align=left][size=17px]public class IndexController { [/size][/align][align=left][size=17px]                          @RequestMapping("index")[/size][/align][align=left][size=17px]        public void index(String code, Model model, HttpServletResponse response,HttpServletRequest request)  {[/size][/align][align=left][size=17px]                             //如果有code就可以去获取用户的open id[/size][/align][/b]                             if(code!=null) {            //通过code来换取access_token
                                 JSONObject json = WeChatUtil.getWebAccessToken(code);            //获取用户openid
                                String openid = json.getString("openid");            //设置到会话中
                                request.getSession().setAttribute("openid",openid);            //重定向到主页
                                response.sendRedirect("/index.html");
           }else{            //重定向到授权页面
                     response.sendRedirect(WeChatUtil.WEB_REDIRECT_URL.replace("APPID",WeChatUtil.APPID)
                         .replace("REDIRECT_URI", RequestUtil.getUrl(request)));
             }
       }
 }
 
注意: 1. WeChatUtil.getWebAccessToken 方法在网页授权的文章中有介绍。
2. WEB_REDIRECT_URL 是网页授权的地址常量:
public static final String WEB_REDIRECT_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?" +
               "appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base#wechat_redirect";

2.点击商品后跳转到商品详细页面
具体页面根据自己的项目添加,主要是页面需要提供一个可以马上下订单的按钮即可。(这里不演示加入购物车功能)


点击立即购买按钮跳转到后台下单地址,并带上当前商品的id。

[AppleScript] 纯文本查看 复制代码
?
1
2
3
4
5
6
7
<script>
   $(function () {        //立即购买按钮
         $("#orderBtn").click(function(){            //获取商品id
          var id = $("#productId").val();            //提交到下单
           window.location.href = "/order.do?productId="+id;
       })
   })</script>

3.接收商品参数并调用微信支付统一下单接口
正常的业务流程是在该方法中,获取商品id,再通过id去查询数据库该商品的相关属性,比如名称,价格等等,然后再创建业务订单,再去调用微信支付的统一下单接口(让微信生成预支付单,后续才可以进行支付)。
但此处重点在支付流程,商品的属性值和订单相关值,暂且先使用假数据。
接口以及参数可参考微信官方提供的统一下单文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
根据文档介绍,我们调用统一下单接口时需要带上相关必填的参数如下:


1.PNG
把必填的参数封装成对应的实体类:


调用接口成功后返回的结果也封装成实体类:

该结果中最重要的是prepay_id参数,在页面中弹出支付窗口时需要用到。

注意:下单的业务逻辑,正常是需要抽取到业务层的,但是此处为了方便阅读代码,直接写到了控制器上。

[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
[/b]
[b]@Controller[/b]
[b]public class OrderController { [/b]
[b]    @RequestMapping("order") [/b]
[b]   public String save(Long productId,Model model,HttpServletRequest request) throws Exception {        //根据商品id查询商品详细信息(假数据)
       //productService.getProductById(productId)
         double price = 0.01;//(0.01元)
         String productName = "SweetCity";        //生成订单编号
         int number = (int)((Math.random()*9)*1000);//随机数
         DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");//时间
         String orderNumber = dateFormat.format(new Date()) + number;        //获取openId
         String openId = (String) request.getSession().getAttribute("openid");        //准备调用接口需要的参数
        WxOrderEntity order = new WxOrderEntity();        //公众号appid
       order.setAppid(WeChatUtil.APPID);        //商户号
       order.setMch_id(WeChatUtil.MCH_ID);        //商品描述
       order.setBody(productName);        //设备号,公众号支付直接填WEB
       order.setDevice_info("WEB");        //交易类型
       order.setTrade_type("JSAPI");        //商户订单号
       order.setOut_trade_no(orderNumber);        //支付金额(单位:分)
       order.setTotal_fee((int)(price*100));        //用户ip地址
       order.setSpbill_create_ip(RequestUtil.getIPAddress(request));        //用户openid
       order.setOpenid(openId);        //接收支付结果的地址
       order.setNotify_url("http://www.wolfcode.com/receive.do");        //32位随机数(UUID去掉-就是32位的)
       String uuid = UUID.randomUUID().toString().replace("-", "");
       order.setNonce_str(uuid);        //生成签名
       String sign = WeChatUtil.getPaySign(order);
       order.setSign(sign);        //调用微信支付统一下单接口,让微信也生成一个预支付订单
       String xmlResult = HttpUtil.post(GET_PAY_URL,XMLUtil.toXmlString(order));        //把返回的xml字符串转成对象
      WxOrderResultEntity entity = XMLUtil.toObject(xmlResult,WxOrderResultEntity.class);        //如果微信预支付单成功创建,就跳转到支付订单页进行支付
      if(entity.getReturn_code().equals("SUCCESS")&&entity.getResult_code().equals("SUCCESS")){            //jssdk权限验证参数
     TreeMap<Object, Object> map = new TreeMap<>();
      map.put("appId",WeChatUtil.APPID);            long timestamp = new Date().getTime();
      map.put("timestamp",timestamp);//全小写
      map.put("nonceStr",uuid);
      map.put("signature",WeChatUtil.getSignature(timestamp,uuid,RequestUtil.getUrl(request)));
      model.addAttribute("configMap",map);            //微信支付权限验证参数
      String prepayId = entity.getPrepay_id();
      TreeMap<Object, Object> payMap = new TreeMap<>();
      payMap.put("appId",WeChatUtil.APPID);
       payMap.put("timeStamp",timestamp);//驼峰
       payMap.put("nonceStr",uuid);
       payMap.put("package","prepay_id="+prepayId);
      payMap.put("signType","MD5");
      payMap.put("paySign",WeChatUtil.getPaySign(payMap));
       payMap.put("packageStr","prepay_id="+prepayId);
       model.addAttribute("payMap",payMap);
     }        //跳转到查看订单页面
       return  "order";
   }
}

下面是jssdk中config权限使用到的的签名,以及微信支付使用的签名的算法代码。
官方文档参考:
config签名:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
pay签名:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
    * 计算jssdk-config的签名
    * @param timestamp
    * @param noncestr
    * @param url
    * @return
    */
   public static String getSignature(Long timestamp,String noncestr,String url ){ [/b]
[b]     //对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)
  Map<String,Object> map = new TreeMap<>();
  map.put("jsapi_ticket",getTicket());
  map.put("timestamp",timestamp);
  map.put("noncestr",noncestr);
  map.put("url",url);        //使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1
  StringBuilder sb = new StringBuilder();
  Set<String> set = map.keySet();        for (String key : set) {
  sb.append(key+"="+map.get(key)).append("&");
       }        //去掉最后一个&符号
   String temp = sb.substring(0,sb.length()-1);        //使用sha1加密
  return SecurityUtil.SHA1(temp);
   }    /**
    * 计算微信支付的签名
    * @param obj
    * @return
    * @throws IllegalAccessException
    */
   public static String getPaySign(Object obj) throws IllegalAccessException, IOException {
  StringBuilder sb = new StringBuilder();        //把对象转为TreeMap集合(按照key的ASCII 码从小到大排序)
  TreeMap<String, Object> map;        if(!(obj instanceof Map)) {
  map = ObjectUtils.objectToMap(obj);
       }else{
  map = (TreeMap)obj;
       }
  Set<Map.Entry<String, Object>> entrySet = map.entrySet();        //遍历键值对
  for (Map.Entry<String, Object> entry : entrySet) {            //如果值为空,不参与签名
  if(entry.getValue()!=null) {                //格式key1=value1&key2=value2…
  sb.append(entry.getKey() + "=" + entry.getValue() + "&");
  }
  }        //最后拼接商户的API密钥
  String stringSignTemp = sb.toString()+"key="+WeChatUtil.KEY;        //进行md5加密并转为大写
  return SecurityUtil.MD5(stringSignTemp).toUpperCase();
   }

4.提供订单展示页面

若对微信JS-SDK不了解的同学可先参考该文章:
https://www.jianshu.com/p/b3c4450f845e
在页面中调用微信JS-SDK,通过config接口注入权限验证配置,并且添加支付功能
[AppleScript] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!--jquery-->
   <script src="/js/jquery.min.js" type="text/javascript" charset="utf-8"></script>
   <!--微信的JSSDK-->
   <script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
   <script>
  $(function() {
  <!--通过config接口注入权限验证配置-->
    wx.config({                debug: true, // 开启调试模式
    appId: '${configMap.appId}', // 公众号的唯一标识
    timestamp: '${configMap.timestamp}', // 生成签名的时间戳
    nonceStr: '${configMap.nonceStr}', // 生成签名的随机串
   signature: '${configMap.signature}',// 签名
   jsApiList: ['chooseWXPay'] // 填入需要使用的JS接口列表,这里是先声明我们要用到支付的JS接口
           });            <!-- config验证成功后会调用ready中的代码 -->
   wx.ready(function(){
  //点击马上付款按钮
  $("#payBtn").click(function(){
   //弹出支付窗口
  wx.chooseWXPay({
  timestamp: '${payMap.timeStamp}', // 支付签名时间戳,
  nonceStr: '${payMap.nonceStr}', // 支付签名随机串,不长于 32
  package: '${payMap.packageStr}', // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=xxxx)
  signType: '${payMap.signType}', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
  paySign: '${payMap.paySign}', // 支付签名
  success: function (res) {
  // 支付成功后的回调函数
  alert("支付成功!");
  }
  });
  })
  });
  });    </script>

点击马上付款后可弹出支付窗口:

支付完成:

5.支付结果的处理
当用户支付后,微信会把支付结果发送到我们前面指定的notify_url地址,我们可以根据支付结果的参数来做相关的业务逻辑,但这里暂不实现,具体支付通知结果的参数可参考官方文章:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8

作者:陈惠
链接:https://www.jianshu.com/p/9c322b1a5274

一文快速实现微信公众号支付功能相关推荐

  1. 一文快速实现微信公众号支付功能(详细版,建议收藏备用)

    进阶架构精品专题 Mysql优化专题(★★★★) 网络协议专题(★★★★) 其余18大专题,请在主页菜单栏查看 后台回复[加群],获取BAT真实面经 微信支付类型 微信支付实际上有很多种不同的类型,具 ...

  2. 微信公众平台开发[3] —— 微信公众号支付功能(PHP)

    直言无讳,我就是一个初涉微信开发的小白,写这篇博客的原因:一是为了给自己做下备忘记录,以便以后能回忆这条程序猿的坎坷路:二是希望能帮助到同是自学开发的小白们:三是对那些不屑一顾于我等尘埃的大牛们的控诉 ...

  3. 前端微信公众号支付功能实现

    前端在拉起微信支付页面之前会有一个预支付的 onLoad(options) {this.obj = JSON.parse(options.obj);console.log("返回的订单数据& ...

  4. 支付宝H5,微信H5,微信公众号支付回调

    业务场景 应公司需求,需要在项目中接入支付宝h5支付,微信h5支付和微信公众号支付功能,本编主要讲述支付踩坑和h5支付后跳转的回调问题 微信h5支付 微信h5支付时需要校验下单域名,微信从refere ...

  5. php调用微信公众号支付接口,Thinkphp微信公众号支付接口

    本文实例为大家分享了Thinkphp微信公众号支付接口,供大家参考,具体内容如下 第一步 先把文件夹的那两个图片 配置成一样的路径 除了域名要改 其他保持一致. 第二步  把 Weixinpay 这个 ...

  6. php微信公众号支付接口案例,Thinkphp微信公众号支付接口

    本文实例为大家分享了Thinkphp微信公众号支付接口,供大家参考,具体内容如下 第一步 先把文件夹的那两个图片 配置成一样的路径 除了域名要改 其他保持一致. 第二步 把 Weixinpay 这个文 ...

  7. yii2嵌入微信公众号支付

    序言 随着微信被越来越多的人使用,微信商城成为如今的热门.每一个商城都需要有自己的支付方式,微信商城也不例外.微信公众号支付就是微信商城的一种支付方式,微信支付随着微信的推广使用也被广泛应用.今天我主 ...

  8. 微信公众号页面支付接口java,[Java教程]微信公众号支付(三):页面调用微信支付JS并完成支付...

    [Java教程]微信公众号支付(三):页面调用微信支付JS并完成支付 0 2015-09-15 15:00:30 一.调用微信的JS文件 1.首先要绑定[JS接口安全域名],"公众号设置&q ...

  9. vue 微信公众号支付接口_基于vue的h5项目之支付宝支付与微信支付

    本文仅记录基于vue开发h5项目过程中使用支付宝和微信支付过程中的重点与槽点,仅为前端部分,如有疏漏不正之处,请于文末评论探讨.注意:标红部分灰常重要,仔细阅读官方文档非常重要,耐心非常重要,细心非常 ...

最新文章

  1. 目标检测的常用数据处理方法!
  2. 2019年1月计算机书籍JavaScript新书
  3. SAP CRM RDS快速部署解决方案
  4. android判断参数非空,Android Studio注释模板Live Templates参数获取不到为null的一些
  5. linux 解压rar密码,linux下rar包的压缩与解压方案
  6. requests爬取免费代理2
  7. linux删除用户删不了怎么办,Linux下完全删除用户的两种方法
  8. Chrome development tools学习笔记(3)
  9. obs计算机丢失,安装obs时提醒没法启动此程序,因为计算机丢失
  10. Duplicate methods named spliterator with the parameters () and () are inherited from the types Colle
  11. Web3.0中国峰会将于7月在成都召开
  12. python编辑数学公式_最好用的文字与公式编辑器,这套数学笔记神器送给你
  13. openresty性能调优
  14. 【IoT】产品设计:如何挖掘产品需求
  15. 几个可以整蛊你朋友的 Python 程序
  16. Windows 7笔记本创建wifi热点供手机上网教程
  17. 苹果手机屏幕上有白点怎么办
  18. java窗体怎么实现下拉菜单_java之swing下拉菜单实现方法
  19. win10 关闭自动维护计划任务
  20. C语言练习:该存多少钱

热门文章

  1. 网课查题公众号怎么搭建制作怎么弄
  2. 第4章 信息系统管理
  3. outlook 日历共享_如何与他人共享Google日历
  4. echarts x轴像直尺一样设置刻度_Python matplotlib画图y轴数值不按大小排列问题
  5. linux 在线模拟器
  6. 永辉超级物种,走到了十字路口?
  7. LInux查看文件时怎么让文件显示行号
  8. sql_mode严格模式(ANSI/TRADITIONAL/STRICT_TRANS_TABLES)
  9. 什么是缓存穿刺和缓存雪崩?如何解决缓存穿透,缓存雪崩
  10. Allegro软件中沉板的器件封装应该怎么处理呢?