一个支持微信、支付宝“一码多付”共享按摩系统的诞生
故事开头怎么写呢,大概2016年10月份吧,当时出差飞机刚落地,久未联系的同学打来电话,说在创业做共享按摩椅,需求说的很简单,扫码支付启动。当时市场上共享按摩椅才兴起,由于平时工作不涉及支付,相关硬件通信模块更是了解甚少,就给回绝了。然后在回去的路上在想,不可能一辈子coding吧,支付、物联网会越来越火,怎么就不能尝试一下呢。
俗话说隔行如隔山,外行看来很简单的需求,不就扫码支付成功后硬件启动。既然想尝试,就详细了解下需求,然后把功能分解一下
过程娓娓道来,先看系统吧。http://m.xyxspace.com 【测试系统地址 】
登录账号可关注上面微信公众号,回复“测试账号”获得。若登录失败,密码可能被其他人修改,可在公众号回复“重置密码”后,后台会自动初始化账号信息,此功能可在系统后台配置。系统demo发邮件至540769049@qq.com,标明来由。
系统架构图
系统业务逻辑流程图
系统功能
1)后台管理模块
a)硬件设备管理
- 设备的增删改查,导出
- 设备上所贴二维码的生成
- 设备的定价
- 设备在线状态、信号强度、grps坐标的更新
b)会员管理
- 会员的增删改查,导出
- 会员余额,积分的管理
c)代金券管理
- 关注公众号、绑定手机号码,自动赠送代金券
- 给指定合作商户批量生成代金券,给指定用户批量绑定代金券,代金券的批量导出
- 代金券的增删改查
- 代金券的过期失效
d)订单管理
- 订单的删查,导出
e)统计功能
- 收入明细
- 按所属网点、每一台设备从微信、支付宝、投币维度统计指定时间点的收入详情
- 统计指定时间范围内每天的收入趋势
- 统计指定时间范围内每小时的收入趋势
f)充值功能
2)支付模块
支持微信、支付宝扫码支付。
3)物联网模块
与硬件设备的通信,控制硬件设备。
一:从无到有,系统搭建
很多系统功能如用户注册、登录、权限,菜单管理等等,都是通用的,这里借鉴了一个成熟的通用框架(https://blog.csdn.net/wernisng090/article/details/50864520),写的挺好,简单了解一下实现过程,直接在此基础上修改了。
二:按照业务流程图一一道来
1.用户扫码
- 入口
@RequestMapping(value = "/{numericPart:[\\d]*}")public ModelAndView scaning() {String url = request.getRequestURL().toString();String mcode = url.substring(url.lastIndexOf("/") + 1);session.setAttribute("mcode", mcode);String id = "";if (Constants.WEIXIN.equals(appType)) {// 来自微信logger.info("微信扫码...");id = (String) session.getAttribute("openid");} else if (Constants.ALIPAY.equals(appType)) {// 来自支付宝logger.info("支付宝扫码...");id = (String) session.getAttribute("user_id");}if (StringUtils.isBlank(id)) {// session中未存在用户信息时,授权重新获取用户信息return indexService.createRedirectURL(appType,mcode);} else {return commonService.trunView(id, mcode, basePath);// 跳转到首页价格页面}}public ModelAndView createRedirectURL(String appType,String mcode) {if (Constants.WEIXIN.equals(appType)) {// 微信客户端String redirectUrl = OAuthManager.generateRedirectURI(WXConstants.REDIRECT_URI, WXConstants.SCOPE, mcode);return new ModelAndView("redirect:" + redirectUrl);} else if (Constants.ALIPAY.equals(appType)) {// 支付宝客户端String redirectUrl = OAuthALiService.generateRedirectURI(AlipayConfig.REDIRECTURI, AlipayConfig.ALIPAY_SCOPE, mcode);return new ModelAndView("redirect:" + redirectUrl);} else {ModelAndView mv = new ModelAndView();mv.setViewName("view/index/unAllow");return mv;}}
- 判断客户端类型
String userAgent = request.getHeader("user-agent");if (StringUtils.isNotBlank(userAgent)) {userAgent = userAgent.toLowerCase();if (userAgent.indexOf("micromessenger") > -1) {// 微信客户端return Constants.WEIXIN;} else if (userAgent.indexOf("alipayclient") > -1) {return Constants.ALIPAY;}}
2.授权获取用户信息
- 微信
2018-08-10 14:29:29,927 INFO [com.xyx.controller.IndexController] - <微信扫码...>
2018-08-10 14:29:34,583 INFO [com.xyx.wx.controller.WXController] - <weixin回调方法...>
2018-08-10 14:29:34,852 INFO [com.xyx.wx.controller.WXController] -
<oauth2获取到的用户信息:[GetUserinfoResponse{openid='o6QuCwb26Pxx1wKkR8CfF9WXoRjU', nickname='她', sex='1', province='河南', city='郑州', country='中国', headimgurl='http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoSibuECOFWda0OseruXfvAWp2GLs0LiceQ87mImXkMRDpAwz9ddNxZatgzroqamaRvWd9hEHTs4xCA/132', privilege=[], unionid='null'}]>
- 支付宝
2018-08-10 14:31:55,456 INFO [com.xyx.controller.IndexController] - <支付宝扫码...>
2018-08-10 14:32:01,387 INFO [com.xyx.alipay.controller.AlipayController] - <ali授权回调方法>
2018-08-10 14:32:01,963 INFO [com.xyx.alipay.controller.AlipayController] -
<{"alipay_user_info_share_response":{"code":"10000","msg":"Success","avatar":"https:\/\/tfs.alipayobjects.com\/images\/partner\/T1fV0vXhpbXXXXXXXX","city":"北京市","gender":"m","is_certified":"T","is_student_certified":"T","nick_name":"neversayd","province":"北京","user_id":"2088012705591342","user_status":"T","user_type":"2"},"sign":"aONatLtOKIl0eWhapZ9VwA+2FupRWE5JM8c353ZrA+VEvmPSvY6E8RObNnXewTvKWL7Jom4WDAOBO8NqE7QfwKYU1WpBEPTe/Ysms+d3ROcvRbhNZiPAgTIpD1hwLR+49oyTtdKrZaUgE+u+T5LE/GL8mx0XHR2Msd9nfJ8O2LsoCtT2EeKSlBazRATcErAoGXciVik7DS9mj9CCXUyYR17kVZgYbROVbvKJNPpT+bPLRL3jH7ofPgh3VR4xmngT2cUHg/qyMaH6vWX4ZsYQgRdLldLga43HWLlU4Nya9haQZFIPzKZNZbhzOqyA7upUaFJFM9vHDkuWQHNM4/ojaA=="}>
- 用户列表
二:支付模块
一码多付,使用微信公众号支付,支付宝手机网站支付功能。
可参考之前写的一个blog,所示代码都是从本系统里摘抄的,https://mp.csdn.net/postedit/79003172
三:微信公众号
- 微信消息事件分发,event事件分发(接口中相应抽象方法已定义,子类继承实现即可)
/*** 消息事件分发*/private void dispatchMessage(){logger.info("distributeMessage start");if(StringUtils.isBlank(wechatRequest.getMsgType())){logger.info("msgType is null");}MsgType msgType = MsgType.valueOf(wechatRequest.getMsgType());logger.info("msgType is " + msgType.name());switch (msgType) {case event:dispatchEvent();break;case text:onText();break;case image:onImage();break;case voice:onVoice();break;case video:onVideo();break;case shortvideo:onShortVideo();break;case location:onLocation();break;case link:onLink();break;default:onUnknown();break;}}/*** event事件分发*/private void dispatchEvent() {EventType event = EventType.valueOf(wechatRequest.getEvent());logger.info("dispatch event,event is " + event.name());switch (event) {case CLICK:click();break;case subscribe:subscribe();break;case unsubscribe:unSubscribe();break;case SCAN:scan();break;case LOCATION:location();break;case VIEW:view();break;case TEMPLATESENDJOBFINISH:templateMsgCallback();break;case scancode_push:scanCodePush();break;case scancode_waitmsg:scanCodeWaitMsg();break;case pic_sysphoto:picSysPhoto();break;case pic_photo_or_album:picPhotoOrAlbum();break;case pic_weixin:picWeixin();break;case location_select:locationSelect();break;case kf_create_session:kfCreateSession();break;case kf_close_session:kfCloseSession();break;case kf_switch_session:kfSwitchSession();break;default:break;}}
/*** 微信消息类型,大小写对应微信接口,msgType的枚举值*/
public enum MsgType {event, //事件text, //文本消息image,location,link,voice,video,shortvideo, //小视频消息music,news,transfer_customer_service;//客服系统
}/*** 微信事件类型*/
public enum EventType {subscribe, //关注unsubscribe, //取消关注/** 创建菜单使用 */click, CLICK, //点击/** 创建菜单使用 */view, VIEW, //跳转链接SCAN, //扫描LOCATION, //上报地理位置TEMPLATESENDJOBFINISH, //模板消息发送成功之后事件scancode_push, //扫码推事件scancode_waitmsg, //扫码推事件且弹出“消息接收中”提示框的事件pic_sysphoto, //弹出系统拍照发图的事件pic_photo_or_album, //弹出拍照或者相册发图的事件pic_weixin, //弹出微信相册发图器的事件location_select, //弹出地理位置选择器的事件media_id, //下发消息(除文本消息)view_limited, //跳转图文消息URL kf_create_session, //接入会话kf_close_session, //关闭会话kf_switch_session, //转接会话
}
- 微信access_token、jsapi_ticket中控服务器
可参考之前写的另一篇blog,所示代码都是从本系统里摘抄的,https://blog.csdn.net/gotohomebye/article/details/78768112
- 微信模板消息(支付成功后的消息通知,账户信息通知)
- 微信菜单管理
/*** 微信菜单*/
public class Menu {private List<MenuButton> button;public List<MenuButton> getButton() {return button;}public void setButton(List<MenuButton> button) {this.button = button;}}
/*** 菜单按钮*/
public class MenuButton {private EventType type;//菜单的响应动作类型private String name;//菜单标题,不超过16个字节,子菜单不超过40个字节private String key;//click等点击类型必须 菜单KEY值,用于消息接口推送,不超过128字节private String url;//view类型必须 网页链接,用户点击菜单可打开链接,不超过256字节private String mediaId;//media_id类型和view_limited类型必须 调用新增永久素材接口返回的合法media_idprivate List<MenuButton> subButton;//子菜单,每个一级菜单最多包含5个二级菜单}/*** 菜单按钮类型*/
public enum MenuButtonType {/** 点击 */click,/** 跳转URL */view,/** 扫码推事件 */scancode_push,/** 扫码推事件且弹出“消息接收中”提示框 */scancode_waitmsg,/** 弹出系统拍照发图 */pic_sysphoto,/** 弹出拍照或者相册发图 */pic_photo_or_album,/** 弹出微信相册发图器 */pic_weixin,/** 弹出地理位置选择器 */location_select,/** //下发消息(除文本消息) */media_id,/** 跳转图文消息URL */view_limited;
}/*** 微信菜单操作*/
public class MenuManager {private static Logger logger = Logger.getLogger(MenuManager.class);private static final String MENU_CREATE_POST_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=";private static final String MENU_GET_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=";private static final String MENU_DEL_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=";private String accessToken;public MenuManager() {this.accessToken = TokenProxy.accessToken();}/*** 创建菜单* @throws WeChatException */public void create(Menu menu) throws WeChatException{logger.info("创建菜单");String resultStr = HttpUtils.post(MENU_CREATE_POST_URL+this.accessToken, JSON.toJSONString(menu));WeChatUtil.isSuccess(resultStr);}/*** 查询菜单*/public Menu getMenu() { logger.info("查询菜单");String resultStr = HttpUtils.get(MENU_GET_GET_URL+this.accessToken);try {WeChatUtil.isSuccess(resultStr);} catch (WeChatException e) {e.printStackTrace();return null;}JSONObject menuObject = JSONObject.parseObject(resultStr);Menu menu = menuObject.getObject("menu", Menu.class);return menu;}/*** 删除菜单* @throws WeChatException */public void delete() throws WeChatException{logger.info("删除菜单");String resultStr = HttpUtils.get(MENU_DEL_GET_URL+this.accessToken);WeChatUtil.isSuccess(resultStr);}
四:支付宝支付
五:系统技术
使用springmvc+mybatis3.2后台框架,mysql5.7数据库,HTML5+css3.0+bootstrap前端页面,redis、shiro 、ehcache 、druid等技术。
- mysql5.7 保存微信emoj表情
- 设备上所张贴二维码的自动生成
- redis数据库的使用(缓存订单,保存每台设备的定价,设备启动倒计时)
- 短信网关(绑定手机号码赠送代金券)
- 邮件系统(发送提醒邮件)
- 系统部署在阿里云上
- 域名的备案
一个支持微信、支付宝“一码多付”共享按摩系统的诞生相关推荐
- 新版开运网运势测算网站源码 支持微信/支付宝H5支付 支持分销代理 可封装APP
源码介绍 我在外面花钱购买的某站VIP资源,就是那种搬砖站,买来没时间调试发给大家看看吧,喜欢的就下去玩玩! 支持微信/支付宝H5和电脑端扫码支付.手机端可以调起微信/支付宝应用支付 支持后台设置价格 ...
- 微信支付宝收款码转账H5免签高并发出码带备注可回调成功率99.9%支持重复支付
微信支付宝收款码转账H5免签高并发出码带备注可回调成功率99.9%支持重复支付多种轮询规则提高存活率 本收款系统,可使用支付宝个人码 企业支付宝收款码 微信个人码收款,可以完成即时到账 ...
- 苹果+android+扫码支付,苹果iOS12捷径扫码付款怎么设置 微信支付宝扫码二合一支付捷径...
苹果iOS12捷径扫码付款怎么设置 微信支付宝扫码二合一支付捷径.捷径是苹果手机一个比较实用的功能,如今手机扫码支付非常流行,因此在苹果手机中安装一个支付捷径,还是非常方便的.下面小编就来分享一个微信 ...
- 微信支付宝扫码支付聚合系统
一.简介 微信支付宝扫码支付聚合系统,聚合了微信支付和支付宝的所有扫码支付模式.并支持微信支付服务商子商户模式.支持五种扫码技术. 二.主要功能 1. 微信扫码支付:包括扫码支付模式一.扫码支付模式二 ...
- 微信支付宝二码合一开发(java)
微信支付宝二码合一开发(java) 1.通过请求的User-Agent来区分是微信还是支付宝 (HttpServletRequest request) request.getHeader(" ...
- 群收收 - 专业微信支付宝付费进群/收费群系统
群收收是一款付费进群系统,可以实现用户先微信/支付宝支付后展示群二维码:用户扫描进Q,同时也适用于付费下载资料. 目前大家都提倡知识付费,但是如何让用户付费后再进入群聊呢?微信官方是不支持的,那么我们 ...
- 微信支付宝扫码支付简介
微信平台 支付模式 付款码支付 Native支付 JSAPI支付 APP支付 H5支付 小程序支付 各种模式的定义可以查看微信官方文档 这里应用Native支付,它是商户系统按微信支付协议生成支付二维 ...
- 网页分享功能 支持 微信二维码 qq空间 qq好友 新浪微博 百度贴吧 豆瓣 人人...
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 2021年最新易支付修复版源码支持微信支付宝官方接口和码支付网信钱包等/个人也能用的易支付商户系统
介绍: 安装环境介绍:Linux + Nginx1.1x +PHP7.2 +MySql5.6 集合了微信官方+支付宝官方+易商户+码支付+易通商户+网信钱包免签即时到账接口,让个人用户也能用上好用的易 ...
最新文章
- 神经网络基础知识梳理
- iframe高度宽度自适应(转)
- 各种平台下Perl模块的安装方法
- android gridview控件使用详解_Android开发实现自定义日历、日期选择控件
- 某8位微型计算机地址码为18位,2015广东海洋大学计算机组成原理试题
- leetcode113. 路径总和 II
- orm2 中文文档 8. 聚合
- 那些Python意想不到的对象
- JQuery Mobile - 固定住页面和页脚
- 【我的Android进阶之旅】Android开发之NDK相关版本下载链接
- 15 分钟 教你搞一个专属于你的域名邮箱
- 微信公众号测试号申请
- day1 开始blog打卡之路
- 阿里云服务器 云对象存储OOS(一) ---入门级操作
- ipad端网页屏幕变小了
- 【博学谷学习记录】超强总结,用心分享 | shell基础
- 游戏化方式学习Git指令
- 北航计算机学院硕士培养方案,北航硕士研究生培养方案.doc
- iOS二维码生成及扫码
- Hash算法解决冲突的方法
热门文章
- 2019-9-2-windows-10「设置」应用完整ms-settings快捷方式汇总
- 数据分析之正态分布检验及python实现
- 用开源组件搭建一套SIEM/SOC/SOAR平台
- python wraps
- ResNet之三——参数调整及网络构建的理解
- Shell之常用命令(diff、path、cut、sort、uniq、tr、path)
- 户外最好的装备是高清卫星地图通过gmap gee地图寻找露营点,野钓
- 【排序算法】图解简单选择排序(图解堪比Debug显示每次循环结果)
- 百度黄埔学院将培养一批首席AI架构师,为“国之重器”赋能
- jquery 左侧下拉菜单