以下内容仅供学习交流,请勿直接用于商业活动

============细节问题===============

经过长时间实践,发现微信和支付宝通知并不是很稳定,有时候会有漏消息的可能,这样对业务会造成很大影响,有些银行的二维码收款可以订阅短信通知,监听短信通知十分稳定,

经过长达数月的测试,没有一起遗漏,所以值得试试,唯一的缺点是短信接收有点延迟,有时长达1分钟左右

==========================================

最近闲来无事,看到网上有一些免签支付回调的服务商,当时感觉很新奇,于是自己动手看看怎么玩的,先看成果

App上监听通知并向服务器POST支付信息

服务端的支付订单表

下面说原理及流程

1.App上使用NotificationListenerService监听通知栏通知,一旦微信支付或者支付宝收款收到消息,读取消息的内容,然后使用正则匹配金额

2.App读取到金额后,构造支付订单,支付订单包含:订单号(App自己生成,不是真实的支付方订单号),金额,App端标识,支付方式,签名(保证数据不被篡改)

3.App将订单POST到填写的URL中

4.服务端收到订单信息,先校验签名是否相符,再查看订单是否存在(防止重放攻击),验证通过后存入数据库,并向指定的回调地址发起请求

5.服务端如果向指定的回调地址发起请求失败,使用定时任务重复发起回调,直到回调成功或达到指定次数

以上就是全部过程,服务端使用springboot,可以很快速搭建

当然为了保证可靠性需要给App加固,防止退出,还有这种只能读取到金额,其他信息一无所知,有些局限性

上代码

App部分

继承NotificationListenerService重写onNotificationPosted方法

//来通知时的调用@Overridepublic void onNotificationPosted(StatusBarNotification sbn) {Notification notification = sbn.getNotification();if (notification == null) {return;}Bundle extras = notification.extras;if (extras != null) {//包名String pkg = sbn.getPackageName();// 获取通知标题String title = extras.getString(Notification.EXTRA_TITLE, "");// 获取通知内容String content = extras.getString(Notification.EXTRA_TEXT, "");Log.i(TAG, String.format("收到通知,包名:%s,标题:%s,内容:%s", pkg, title, content));//处理processOnReceive(pkg, title, content);}}/*** 消息来时处理** @param pkg* @param title* @param content*/private void processOnReceive(String pkg, String title, String content) {if (!AppConstants.LISTEN_RUNNING) {return;}if ("com.eg.android.AlipayGphone".equals(pkg)) {//支付宝if (checkMsgValid(title,content,"alipay") && StringUtils.isNotBlank(parseMoney(content))) {TreeMap<String, String> paramMap = new TreeMap<>();paramMap.put("title", title);paramMap.put("content", content);paramMap.put("identifier", AppConstants.CLIENT_IDENTIFIER);paramMap.put("orderid", CommonUtils.randomCharSeq());paramMap.put("gateway", "alipay");String sign = CommonUtils.calcSign(paramMap, AppConstants.SIGN_KEY);if (StringUtils.isBlank(sign)) {Log.e(TAG, "签名错误");return;}HttpTask task = new HttpTask();task.setOnAsyncResponse(this);String json = new Gson().toJson(paramMap);task.execute(AppConstants.POST_URL, "sign=" + sign, json);}} else if ("com.tencent.mm".equals(pkg)) {//微信if (checkMsgValid(title, content, "wxpay") && StringUtils.isNotBlank(parseMoney(content))) {TreeMap<String, String> paramMap = new TreeMap<>();paramMap.put("title", title);paramMap.put("content", content);paramMap.put("identifier", AppConstants.CLIENT_IDENTIFIER);paramMap.put("orderid", CommonUtils.randomCharSeq());paramMap.put("gateway", "wxpay");String sign = CommonUtils.calcSign(paramMap, AppConstants.SIGN_KEY);if (StringUtils.isBlank(sign)) {Log.e(TAG, "签名错误");return;}HttpTask task = new HttpTask();task.setOnAsyncResponse(this);String json = new Gson().toJson(paramMap);task.execute(AppConstants.POST_URL, "sign=" + sign, json);}}}/*** 解析内容字符串,提取金额** @param content* @return*/private static String parseMoney(String content) {Pattern pattern = Pattern.compile("收款(([1-9]\\d*)|0)(\\.(\\d){0,2})?元");Matcher matcher = pattern.matcher(content);if (matcher.find()) {String tmp = matcher.group();Pattern patternnum = Pattern.compile("(([1-9]\\d*)|0)(\\.(\\d){0,2})?");Matcher matchernum = patternnum.matcher(tmp);if (matchernum.find())return matchernum.group();}return null;}/*** 验证消息的合法性,防止非官方消息被处理** @param title* @param content* @param gateway* @return*/private static boolean checkMsgValid(String title, String content, String gateway) {if ("wxpay".equals(gateway)) {//微信支付的消息格式//1条:标题:微信支付,内容:微信支付收款0.01元(朋友到店)//多条:标题:微信支付,内容:[4条]微信支付: 微信支付收款1.01元(朋友到店)Pattern pattern = Pattern.compile("^((\\[\\+?\\d+条])?微信支付:|微信支付收款)");Matcher matcher = pattern.matcher(content);return "微信支付".equals(title) && matcher.find();} else if ("alipay".equals(gateway)) {//支付宝的消息格式,标题:支付宝通知,内容:支付宝成功收款1.00元。return "支付宝通知".equals(title);}return false;}

服务端接收代码

/*** 接受App发送的通知内容* @param content   通知内容json, {"title": "标题", "content": "内容", "identifier": "app端标识", "orderid": "app生成的唯一订单号", "gateway": "wxpay或alipay"}* @param sign      签名,签名方式按照content对应的key1=vaule1&key2=value2...&SECKEY计算md5,key的顺序按字母表的顺序* @return*/@RequestMapping(value = "/c/post/notification", method = { RequestMethod.POST })@ResponseBodypublic String receiveAppNotification(@RequestBody Map<String, Object> content, String sign) {logger.debug("请求参数,content=>{}, sign=>{}", JSON.toJSONString(content), sign);if (StringUtils.isBlank(sign) || CollectionUtils.isEmpty(content)) {return APIUtil.getReturn(APIConst.PARAM_ERROR);}//再次验证字段String contenttext = (String) content.get("content");String identifier = (String) content.get("identifier");String orderid = (String) content.get("orderid");String gateway = (String) content.get("gateway");if (StringUtils.isAnyBlank(contenttext, identifier, orderid, gateway) || !ImmutableList.of("alipay","wxpay").contains(gateway)) {return APIUtil.getReturn(APIConst.PARAM_ERROR);}//读取金额(单位元)Pattern pattern = Pattern.compile("([1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*)");Matcher matcher = pattern.matcher(contenttext);if (!matcher.find()) {return APIUtil.getReturn(APIConst.PARAM_ERROR);}String amountStr = matcher.group(1);logger.debug("解析的金额:{}", amountStr);BigDecimal amount = null;try {amount = new BigDecimal(amountStr);} catch (NumberFormatException e) {logger.error("金额格式错误: {}", amountStr);return APIUtil.getReturn(APIConst.PARAM_ERROR);}//验证签名TreeMap<String, Object> paramMap = new TreeMap<>(content);Iterator<Map.Entry<String, Object>> it = paramMap.entrySet().iterator();StringBuilder sb = new StringBuilder();while (it.hasNext()) {Map.Entry<String, Object> entry = it.next();sb.append(entry.getKey());sb.append("=");sb.append(entry.getValue());sb.append("&");}sb.append(SIGN_KEY);//计算签名String calcSign = MD5Util.MD5Encode(sb.toString(), "UTF-8");if (!calcSign.equalsIgnoreCase(sign)) {return APIUtil.getReturn(1, "签名错误");}//查询订单号是否已经存在boolean exist = orderService.checkOrderExist(orderid);if (exist) {logger.error("订单号:{}已存在", orderid);return APIUtil.getReturn(1, "订单号已存在");}//订单写入数据库String account = "";if (gateway.equals("wxpay")) {account = "W" + identifier;} else if (gateway.equals("alipay")) {account = "A" + identifier;}MqOrder order = new MqOrder();order.setAccount(account);order.setAmount(amount);order.setGateway(gateway);order.setOrderId(orderid);order.setStatus(0);order.setNotifyCount(0);order.setCreateTime(new Date());orderService.save(order);return APIUtil.getReturn(APIConst.OK);}

欢迎学习交流

基于支付宝微信通知的一种个人收款回调方案相关推荐

  1. 支付宝 收款通知 mysql_基于支付宝微信通知的一种个人收款回调方案(转)

    最近闲来无事,看到网上有一些免签支付回调的服务商,当时感觉很新奇,于是自己动手看看怎么玩的,先看成果 App上监听通知并向服务器POST支付信息 服务端的支付订单表 下面说原理及流程 1.App上使用 ...

  2. 个人支付宝/微信/云闪付/商户聚合码/银行卡等到账通知常用技术方案总结

    个人支付宝/微信/云闪付/商户聚合码/银行卡等到账通知常用技术方案总结 通过分析和研究,以及观察目前市面上面已经存在的相关技术方案平台,结合自己最终的实现,整体方案实现,常用架构如下(大部分的只实现了 ...

  3. linux 监控微信通知,一个 Linux 下基于 Bash 的文件和数据库监控及备份工具,可发送微信报警通知...

    shellMonitor 一个 Linux 下基于 bash 的文件和数据库监控及备份工具. 写这个工具的原因,在于一个朋友的一个小电商网站,因为未明原因被黑了,总是会被增加超级管理员,并将收款账号改 ...

  4. 企业微信推送消息延迟_一种基于企业微信的消息推送方法与流程

    本发明涉及消息推送技术领域,特别涉及一种基于企业微信的消息推送方法. 背景技术: 随着微信公众号的普及,微信企业号也越来越受到人们的关注.而腾讯公司在微信企业号的基础上又进行了进一步的升级,提供了类似 ...

  5. 魔坊APP项目-18-种植园,基于支付宝提供的沙箱测试环境开发支付接口、服务端, 处理支付结果的同步通知和异步通知、修复页面底部菜单无法被点击的BUG

    种植园 一.基于支付宝提供的沙箱测试环境开发支付接口 沙箱环境: https://openhome.alipay.com/platform/appDaily.htm?tab=info 开发文档: ht ...

  6. 支付宝微信扫码支付调研

    一.支付宝扫码支付 1.1 系统流程说明 1.1.1 条码支付(被扫) 条码支付是支付宝给到线下传统行业的一种收款方式.商家使用扫码枪等条码识别设备扫描用户支付宝钱包上的条码/二维码,完成收款.用户仅 ...

  7. 支付宝接口使用文档说明 支付宝异步通知

    支付宝接口使用文档说明 支付宝异步通知(notify_url)与return_url. 现支付宝的通知有两类.  A服务器通知,对应的参数为notify_url,支付宝通知使用POST方式  B页面跳 ...

  8. 微信支付宝服务器分布,支付宝微信扫码支付中间件「第二届立创商城电子制作节30强作品」...

    原标题:支付宝微信扫码支付中间件「第二届立创商城电子制作节30强作品」 本作品为第二届立创商城电子制作节30强入围作品,作者立创社区ID:云逸Baby:转载请注明出处,未经允许不得用作商业用途.作品原 ...

  9. 移动支付--银联,支付宝,微信(android)

    在这个移动互联网快速发展的时代,手机已经成为人们生活或者出行之中必不可少的设备了,如今非常多城市的商户都能够採用支付宝,微信支付了.人们出门仅仅须要随身携带带手机.不用带大量现金就能够放心购物了.如今 ...

最新文章

  1. Android 项目版本的修改
  2. 2018-4-17论文《狼群算法的研究与应用》笔记2 :高维复杂单目标连续优化问题的改进狼群算法
  3. 深度整合英特尔傲腾,SmartX首发100us级超低延迟超融合解决方案
  4. Activity和Intent,打电话,发送短信
  5. mac mysql utf 8编码_MacOS下MySQL设置UTF8编码问题
  6. windows API(一)
  7. Java获取近七天的数据条数,及页面实现折线图(附前后端代码)
  8. 数字图像处理与Python实现笔记之彩色图像处理初步
  9. VVC编码进展:码率降低,速度仍需提升
  10. 【免费下载】2021年6月份热门报告盘点
  11. IOS 10.3.3 越狱
  12. 磁盘碎片对计算机系统的影响,磁盘碎片整理第9遍了|Win7磁盘碎片整理的方法
  13. Spring MVC详解(学习总结)
  14. XSS-labs靶场通关秘籍(level 17-20)
  15. CMS与前端页面SSI技术
  16. ⅰcp经济模型_EOQ经济批量模型上篇(模型基础)
  17. 50款巧夺天工的PSD按钮素材
  18. android 阅读pdf 文件,Android实如今线阅读PDF文件
  19. 从iQOOZ1到iQOOZ1x,iQOO何以能持续打造爆款?
  20. 程序员是否应该去做外包

热门文章

  1. 腾讯云CVM云服务器1M宽带能干嘛?1M宽带支撑多少人在线?
  2. 求生之路怎么显示所有服务器,求生之路2怎么屏蔽rpg服务器 求生之路2屏蔽rpg服务器方法_游侠网...
  3. 公司申请微信订阅号需要的材料及注意事项
  4. 【Mac】搜狗输入法干扰声音输出
  5. c# 正则表达式 Group
  6. 虚拟机开机问题:开机时卡在启动窗口
  7. iOS端手游和c++交互 lua和c++交互
  8. A4纸尺寸大小是多少
  9. 后端进度报告(2018.5.17)
  10. 简洁UI设计,超简单的旅游APP,Figma源文件下载