一个支持微信、支付宝“一码多付”共享按摩系统的诞生

news/2024/11/15 5:41:25/

       故事开头怎么写呢,大概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数据库的使用(缓存订单,保存每台设备的定价,设备启动倒计时)
  • 短信网关(绑定手机号码赠送代金券)
  • 邮件系统(发送提醒邮件)
  • 系统部署在阿里云上
  • 域名的备案

http://www.ppmy.cn/news/175694.html

相关文章

懒癌患者必备!Medisana让你在按摩椅上旅游

这款VR按摩椅让你“葛优瘫”也能游遍天下&#xff1f; 在2016 IFA国际消费电子展上&#xff0c;传统医疗保健公司Medisana推出了“VR按摩椅”的项目&#xff0c;可以让用户一边“葛优躺”&#xff0c;一边在VR里感受世界各地的美景。 Medisana提供的按摩椅主要是针对Oculus Rif…

使用 Python 从作为字符串给出的数字中删除前导零

使用的方法 以下是用于完成此任务的各种方法 - 使用 For 循环和 remove&#xff08;&#xff09; 函数使用正则表达式使用 int&#xff08;&#xff09; 函数 方法 1&#xff1a;使用 For 循环和 remove&#xff08;&#xff09; 函数 算法&#xff08;步骤&#xff09; 以…

戴尔笔记本电脑光驱装固态,并设置为系统盘教程

本人笔记本电脑型号为Dell Insoriration 15-3576 拆机教程&#xff0c;并把新换的硬盘装到光驱位置&#xff0c;注意光驱排线插在键盘下&#xff0c;螺丝放好&#xff0c;容易丢&#xff0c;https://haokan.baidu.com/v?pdwisenatural&vid9785087749312452589 装好之后&am…

​戴尔科技集团+微软Azure Stack HCI:引领混合云上云新范式

目前混合云正在成为企业上云的主流选择&#xff0c;这是因为混合云的优势在于能够适应不同的部署需求&#xff0c;既能提供私有云的安全性&#xff0c;也能提供公有云的开放性&#xff0c;因此这也让混合云架构被越来越多的企业所认可并采用。 值得注意的是&#xff0c;作为混合…

戴尔+UnitedStack托管云:不是偶然的合作

云的分布式架构提供了更高程度的弹性和可靠性。 基于开源的OpenStack是最好的云平台技术之一&#xff0c;更有利于最大化用户投资。 戴尔与UnitedStack合作&#xff0c;不仅带来全功能的云计算平台&#xff0c;完善的持续集成体系更为用户持续交付新的价值。 当戴尔与UnitedSta…

新基建新机遇新赋能,戴尔科技吹响Power集结号

每一次技术变革与行业进步&#xff0c;都离不开善于创新、善于赋能的企业。 在遭遇全球疫情的影响下&#xff0c;数字化形态和创新数字基建正在呈现前所未有的发展趋势。深耕中国市场20余年&#xff0c;戴尔科技集团始终不遗余力地推动数字化转型和信息化发展。 自2015年以来&a…

【观察】戴尔科技:引领超融合现代化升级,加速企业迈向多云时代

申耀的科技观察 读懂科技&#xff0c;赢取未来&#xff01; 众所周知&#xff0c;超融合自诞生以来&#xff0c;几乎很快就赢得了市场各方的认可&#xff0c;并从一个相对较小范围的应用领域&#xff0c;逐渐成长为目前企业构建软件定义数据中心&#xff0c;乃至未来实现多云管…

【观察】15季度位列第一,揭秘戴尔超融合家族的“统治力”

申耀的科技观察 读懂科技&#xff0c;赢取未来&#xff01; 最近几年&#xff0c;超融合在中国市场的火爆程度不亚于云计算、人工智能等新技术&#xff0c;自2013年超融合概念首次在中国出现&#xff1b;到2016年中国迎来“超融合元年”&#xff1b;再到这两年超融合开始广泛落…