微信公众号开发-业务开发03
1. 前言
接下来是对业务进行简单的说明。其实这是一个很简单的项目。跟市面上的WiFi故事机是类似的,包含设备局域网发现、Airkiss配网、设备绑定、微信互聊、公众号点播。
2.局域网发现
标准的Airkiss协议里面有自带局域网发现协议,只要在微信公众号后台增加设备功能插件,然后利用Airkiss第三版完整协议,那么可以完成设备的,局域网发现、Airkiss配网、设备绑定。这三个功能。不过我目前做的这个项目,只用到Airkiss的配网,没有用到其他的功能。
局域网发现,我这里的实现方式是,微信公众号网页发送一个HTTP请求到服务器,服务器记录IP地址,设备联网后,同样请求服务器,记录IP地址。如果两者的IP地址是一样的,那么表示两个设备处于同一个局域网。这种方式,在绝大部分情况下,是没有问题的。只是对那些大局域网会有些影响,比如同个小区,只有一个外网地址出口,或者类似于企业或学校,只有少数的外网地址,就会出现,设备被其他人误扫描,绑定。
3.Airkiss配网、超声波配网
这个在公众号页面上用JSSDK调用WiFi配置即可。
1 wx.invoke('configWXDeviceWiFi', { }, function(res) { 2 if(res.err_msg == "configWXDeviceWiFi:ok"){ 3 window.location.href = "/wx/wechat/scan_bind"; 4 }else if(res.err_msg == "configWXDeviceWiFi:fail"){ 5 window.Vue.$toast("配置不成功,可以尝试使用声波配网"); 6 }else if(res.err_msg == "configWXDeviceWiFi:cancel"){ 7 } 8 });
由于网络的复杂性,有时候通过Airkiss配网会不成功,因此需要有其他的辅助性配网方式,本项目使用声波配网。流程是,在界面上输入WiFi的SSID和密码,然后传到服务器,服务器根据自定义算法生成一段WAV的音频文件,然后把这个音频文件放到<audio>标签进行播放。设备通过采集声音,转成对应的SSID和密码。
4.设备绑定
通过上面的,设备局域网发现及配网网络后。就进入设备绑定功能。设备绑定,就是在数据库中记录当前设备的设备ID和当前登录的微信用户。这里公众号唯一确定一个用户的是工作的OpenID。这个OpenID是公众号内用户的唯一凭证。
5.微信互聊
在公众号的聊天窗口中,每次用户向公众号发送信息或者一些事件时,都是会携带OpenID。然后根据OpenID对应绑定的设备ID,向该设备发送语音信息。
这里分为两种情况,一种是用户发送到设备,一种是设备发送到用户。
用户发送到设备的,用户在公众号发送语音信息,会触发微信的一个语音信息事件,我们只需要在语音信息注册一个Handler即可。这里的Handler只会有一个MediaID,服务器还需要通过这个MediaID获取语音二进制AMR音频文件。这个AMR文件可以直接发到设备或存放到服务器。
newRouter.rule().async(false).msgType(XmlMsgType.VOICE).handler(msgvoiceHandler).end();
1 @Component 2 public class WechatMpMsgVoiceHandler extends AbstractHandler { 3 4 @Value("${project.resource.url}") 5 private String voice_prefix; 6 @Value("${project.voice.dir}") 7 private String voiceDir; 8 @Autowired 9 private WechatVoiceCtrlService wechatvoicectrlService; 10 @Autowired 11 private WechatBindService wechatbindService; 12 @Autowired 13 private MQTTPushMessageService mqttpushmessageService; 14 15 @Override 16 public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxmpService, 17 WxSessionManager sessionManager) throws WxErrorException { 18 try { 19 File file = wxmpService.getMaterialService().mediaDownload(wxMessage.getMediaId()); 20 String mediaId = wxMessage.getMediaId(); 21 String filename = TimestampUtils.getCurrentDateDirFormat() + "/" + mediaId; 22 File moveit = new File(voiceDir + "/" + filename); 23 if(!moveit.getParentFile().exists()) { 24 moveit.getParentFile().mkdirs(); 25 } 26 FileUtils.moveFile(file, moveit); 27 String _id = ""; 28 //写入数据库 29 WechatDevicePoModel device = 30 wechatbindService.selectOneWechatDeviceByOpenID(wxMessage.getFromUser()); 31 //System.out.println(device); 32 if(device == null) { 33 return new WechatMpTextBuilder().build("您还未绑定设备哦", wxMessage, wxmpService); 34 } 35 MongoVoiceVoModel voice = new MongoVoiceVoModel(); 36 voice.setData(filename); 37 voice.setDeviceid(device.getDevice_id()); 38 voice.setRand(RandomUtils.getRandomStr()); 39 voice.setRead(false); 40 voice.setTs(TimestampUtils.getCurrentTimestamp()); 41 voice.setType("path"); 42 voice = wechatvoicectrlService.save(voice); 43 if(voice != null) { 44 _id = voice.get_id(); 45 MqttPayloadVoModel<MqttVoiceMessagePayloadVoModel> payload = new MqttPayloadVoModel<>(); 46 payload.setId(RandomUtils.getRandomStr()); 47 payload.setCmd("message_new"); 48 payload.setTs(TimestampUtils.getCurrentTimestamp()); 49 MqttVoiceMessagePayloadVoModel parm = new MqttVoiceMessagePayloadVoModel(); 50 parm.set_id(_id); 51 parm.setTxt(wxMessage.getRecognition()); 52 parm.setUrl(voice_prefix + "?filename=" + voice.getData() + "&access_token="); 53 payload.setParm(parm); 54 System.out.println(payload); 55 mqttpushmessageService.sendWechatNewMessage(device.getDevice_id(), payload); 56 //增加对该设备下的所有用户进行广播 57 List<WechatUserPoModel> users = wechatbindService.selectListWechatUserByDeviceID(device.getDevice_id()); 58 for(int i=0; i<users.size(); i++) { 59 WechatUserPoModel user = users.get(i); 60 if(user.getOpenid().equals(wxMessage.getFromUser())) { 61 continue; 62 } 63 try { 64 wxmpService.getKefuService().sendKefuMessage( 65 WxMpKefuMessage.VOICE().toUser(user.getOpenid()).mediaId(mediaId).build()); 66 }catch (WxErrorException e) { 67 //一些长期没有跟公众号互动的用户会发送失败 68 } 69 } 70 71 return new WechatMpTextBuilder().build("已发送[Yeah!]\n" + wxMessage.getRecognition(), 72 wxMessage, wxmpService); 73 }else { 74 return new WechatMpTextBuilder().build("发送失败", wxMessage, wxmpService); 75 } 76 }catch (Exception e) { 77 e.printStackTrace(); 78 } 79 return new WechatMpTextBuilder().build("发送失败2", wxMessage, wxmpService); 80 } 81 }
另一种情况是,设备发送语音到用户。由于设备是无法直接对接微信服务器,或者说,无法直接上传音频AMR文件到微信。因此,需要把音频文件上传到服务器,服务器再上传到微信服务器,然后获取到临时资源文件的MediaID。再通过设备ID对应绑定的用户的OpenID,发送一个客服信息。
设备上传音频到服务器,服务器上传音频到微信,再通过微信客服接口发送给绑定的用户。
1 /** 2 * 设备->微信用户 3 * @param device_id 4 * @param amr 5 * @return 6 */ 7 public boolean send(String device_id, InputStream input) { 8 try { 9 List<WechatUserPoModel> users = wechatbindService.selectListWechatUserByDeviceID(device_id); 10 if(CheckUtils.isEmpty(users)) { 11 return false; 12 } 13 WxMediaUploadResult result = 14 wxmpService.getMaterialService().mediaUpload( 15 WxConsts.MediaFileType.VOICE, "amr", input); 16 String mediaid = result.getMediaId(); 17 for(int i=0; i<users.size(); i++) { 18 WechatUserPoModel user = users.get(i); 19 try { 20 wxmpService.getKefuService().sendKefuMessage( 21 WxMpKefuMessage.VOICE().toUser(user.getOpenid()).mediaId(mediaid).build()); 22 }catch (WxErrorException e) { 23 //一些长期没有跟公众号互动的用户会发送失败 24 } 25 } 26 return true; 27 } catch (WxErrorException e) { 28 if(e.getError().getErrorCode() == 45047) { 29 //保留语音信息 30 } 31 System.out.println(e.getError().getErrorCode()); 32 e.printStackTrace(); 33 } 34 return false; 35 }
6.公众号点播及展示
公众号H5界面与设备互动,设备与用户两者间需要通过服务器转发信息或命令到对方。这里我使用MQTT作为信息转发中间件。
设备与用户间订阅同个Topic,然后互相发送信息即可。对于设备信息的展示,用户端的命令控制,都是通过MQTT,这里都是一些自定义协议,就不在过多说明了。
7. 前端界面
8.数据库表
用户表
1 create table wechat_user( 2 userid serial primary key, --主键 3 openid text, --公众号下用户OpenID 4 nickname text, --昵称 5 sex_desc text, --性别描述 6 sex int, --性别 7 city text, --城市 8 province text, --省份 9 country text, --国家 10 head_img_url text, --头像 11 subscribe_time bigint, --订阅时间 12 union_id text, -- 13 remark text, -- 14 subscribe_scene text, --订阅渠道 15 status boolean --用户状态 16 );
设备表
1 create table wechat_device( 2 devid serial primary key, --主键 3 device_id text, --设备ID,必须保证全局唯一 4 device_mac text, --设备MAC地址 5 auth_key text, --通讯加密key 32字节16进制串 6 op_type int, --绑定类型 7 op_status int --设备状态 -1禁用 0新建 1生产 2微信验证 8 );
用户-设备绑定表
1 create table wechat_bind( 2 bindid serial primary key, --主键 3 openid text, --用户OpenID 4 device_id text --设备ID 5 );
9.总结
总的来说,这个项目还是没有多少技术含量的,很普通的一个项目,一个多月就把前后端给做了,最后也是没有实际使用。又是一个报废项目。感觉心有点受伤呀!既然花时间做了,还是要简单记录一下。
本文地址: https://www.cnblogs.com/wunaozai/p/9913379.html
作者:无脑仔的小明 出处:http://www.cnblogs.com/wunaozai/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 如果文中有什么错误,欢迎指出。以免更多的人被误导。有需要沟通的,可以站内私信,文章留言,或者关注“无脑仔的小明”公众号私信我。一定尽力回答。 |