微信Native支付
微信Native支付对接(扫码)
由于有业务需求对接了微信和paypal支付,这边做个记录
微信支付开发文档:https://pay.weixin.qq.com/wiki/doc/api/index.html
一、支付方式
这边有个坑,微信h5支付和Native支付都是微信外部使用的支付方式,但是h5支付适用于移动端,因为支付时是从外部唤醒本地移动端的微信app进行支付;而Native支付则是在pc端生成订单后,用户使用移动端的微信app扫码完成支付
- 付款码支付:需要用户有扫码枪.如:肯德基,麦当劳的支付
- JSAPI支付: 主要服务于微信内部调用的支付接口
- Native支付:扫码支付
- h5支付:手机浏览器调用的支付
二、支付流程介绍
用户:客户
前端:ui界面,客户端
后端:java写的服务端
微信系统:包括生产订单的接口等
流程:
- 用户点击前端的支付按钮
- 前端将对应的订单信息发送给后端
- 后端预处理订单的信息(如在数据库中生成对应的记录),然后调用微信支付系统生成订单的接口
- 微信支付系统返回对应订单的支付地址给后端
- 后端将该订单地址返还给前端,前端调用QRCode工具生成二维码
- 用户打开手机微信app扫码完成支付(由于和我们业务并没有直接的相关性,这个过程没有直接在上图中表现出来)
- 微信系统异步(有延时)收到微信支付成功的回调,回调函数中应该包括对于验证订单的有效性(如果被人攻破就麻烦了),存储数据库(确认订单已结算),回复微信系统(否则微信会在一天之内多次发送回调信息)等步骤
- 后端可以通知前端订单完成,以便后续的操作(具体的做法可以是从订单生成之后,前端可以以一定的时间间隔询问订单的状态)
注:其它支付手段的流程应该也是大致相同的
三、准备工作
首先必然是下载sdk(software development kit).值的注意的一点是,对比于网上的许多旧的微信博客,可以发现微信的api有了极大的改进,我们只要调用少许的接口即可完成开发.同时api的命名目前也是比较统一的
-
申请一个商机号
注:商家号的申请是需要相关的营业执照的
-
上微信商户号中开通Native支付的服务
-
准备调用订单支付接口相关的参数(这里只展示一下必填项)
字段名 变量名 描述 公众账号ID appid 微信支付分配的公众账号ID 商户号 mch_id 微信支付分配的商户号 随机字符串 nonce_str 由内置的随机数生成算法生成 签名 sign 由内置的签名算法生成 商品描述 body 商品的简单描述 商品订单号 out_trade_no 可以直接用订单id 标价金额 total_fee 单位为分(CNY) 终端IP spbill_creat 服务器IP 通知地址 notify_url 异步回调的地址(回调不能在本地测试) 交易类型 trade_type NATIVE -Native支付 商品ID product_id 商品id,Native必填 密匙 key 商家自行设置的密匙 - 在微信商户号后台获得appid,mch_id,设置key
- out_trade_no必须大于10,不能重复
- total_fee不能有小数点(正常情况也不应该有小数点)
- nonce_str变量用于提高生成的sign不确定
- sign的算法是先将所有的参数进行排序,然后按key=value的形式拼接为字符串,最后加上key.最后,对拼接后字符串进行加密,加密方式一种是用MD5,一种使用HMAC-SHA256.具体的过程可以查看sdk原码,实际使用只要传入参数map给相关的api即可,但是了解一下有助于调试,另外附加一个微信官方的签名校验工具
- key是保证整个支付过程加密以及回调地址不被攻破的关键!
- 可以用额外的attach附加参数,如订单id
-
sdk下载地址(maven的相关地址大家可以自己去找找):https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1
四、开发工作
这里主要说明一下后端接口的调用
-
调用接口生成订单
public String getWxQrCode(HashMap<String,Object> paraMap) throws Exception { /*数据库操作*/ Integer maxId = userMapper.getMaxUserId(); Integer id = maxId==null?1:maxId+1; paraMap.put("user_id",id); userMapper.addUser(paraMap); /*获得code_url*/ Map<String, String> map = new HashMap<>(); map.put("appid",wxPayConfigBean.getAppID()); map.put("mch_id",wxPayConfigBean.getMchID()); map.put("body",wxPayConfigBean.getBody()); map.put("out_trade_no",id.toString()); map.put("total_fee",paraMap.get("order_amount").toString()); map.put("spbill_create_ip",paraMap.get("ip").toString()); map.put("notify_url",wxPayConfigBean.getNotifyUrl()); map.put("trade_type",wxPayConfigBean.getTradeType()); map.put("attach",id.toString()); //Native必传 map.put("product_id",paraMap.get("order_productid").toString()); //获得sign WXPay wxPay = new WXPay(wxPayConfigBean); Map<String, String> backMap = wxPay.unifiedOrder(map); HashMap<String, Object> resMap = new HashMap<>(); resMap.put("url",backMap.get("code_url")); resMap.put("id",id); return JsonUtil.toJsonString(resMap); } -
回调
public void wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception { //拿到微信回调信息(以字节流的方式) InputStream inputStream = request.getInputStream(); BufferedReader in = new BufferedReader(new InputStreamReader(inputStream,"UTF-8")); //String是字符串变量,StringBuffer是字符串变量 StringBuffer sb = new StringBuffer(); //将字节流转换为字符串 String line; while ((line = in.readLine()) != null){ //每次用line读取一行的字节流,如果这一行不为空就扩展到sb上 sb.append(line); } System.out.println("*****************************sb**************************"); System.out.println(sb); System.out.println("*****************************sb**************************"); //关闭 in.close(); inputStream.close(); String strXml = sb.toString(); Map<String, String> toMap = WXPayUtil.xmlToMap(strXml); System.out.println(toMap); //获取业务信息 String outTradeNo = toMap.get("out_trade_no"); String totalFee = toMap.get("total_fee"); String appId = toMap.get("appId"); String mchId = toMap.get("mch_id"); String resultCode = toMap.get("result_code"); String attach = toMap.get("attach"); //附加数据 //该对象用于通知微信 PrintWriter writer = response.getWriter(); //验签 String res = null; Map<String,String> paraMap = WXPayUtil.xmlToMap(strXml); boolean signatureValid = WXPayUtil.isSignatureValid(paraMap, wxPayConfigBean.getKey(), WXPayConstants.SignType.HMACSHA256); //注:注意返回时有nonce_str if (signatureValid){ System.out.println("验证成功~"); if ("SUCCESS".equals(toMap.get("result_code"))){ System.out.println("返回的是SUCCESS"); /*自己的业务逻辑*/ } //返回值——仍然有问题,不断刷回复 String noticeStr = setXML("SUCCESS",""); writer.write(noticeStr); writer.flush(); //情况缓存区,并完成文件写入操作 } }else{ System.out.println("验证失败"); String noticeStr = setXML("FATL",""); writer.write(noticeStr); writer.flush(); }; } private static String setXML(String return_code, String return_msg) { return "<xml><return_code><![CDATA[" + return_code + "]]></return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>"; }
注:
- 有时候回调好像没有正确地返还个微信支付系统,对java的输入输出不太了解,麻烦有大佬知道问题的请留言
- 在最开始尝试对接微信支付时查阅了较多的博客,代码,在这里表示感谢.但因为实在太过庞杂,就不一一列出了.
__EOF__
本文作者:Arno
本文链接:https://www.cnblogs.com/Arno-vc/p/13735914.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文链接:https://www.cnblogs.com/Arno-vc/p/13735914.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix