请选择 进入手机版 | 继续访问电脑版

智能创客,中国最大的极客空间,智能平台,免费教学,视频教程,手把手教你创造儿时梦想!

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 10232|回复: 4

微信硬件开发系列教程04-微信公众号开发DEMO(airkiss/airsync)

[复制链接]

110

主题

396

帖子

2329

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2329
QQ
发表于 2016-4-12 16:55:57 | 显示全部楼层 |阅读模式
这篇讲解对微信公众号开发DEMO分析,主要的目的是了解它的原理和微信API的使用。
然后进行修改,实现我们想要的功能,如:菜单的创建、信息交互、跳转到自定义HTML5页面等等。



一、目录结构讲解。
bluelightcode010.png
展开目录后,按照1、2、3、4、5的顺序讲解:
1、web.xml网站配置(上面图片标错了,是在WEB-INF未展来的目录里的web.xml)
2、公众账号信息配置。
3、微信推送消息的入口。
4、处理微信消息的业务类。
5、相关微信API的使用方法,创建菜单,进行设备授权,生成二维码等。



二、web.xml(程序引导配置)

bluelightcode020.png
双击web.xml,就会看到网站配置的内容
1、声明地址名称,绑定相关的Servlet类,以后访问就用这个地址。
2、将名称映射到地址。
这样就能成功访问:http://你的域名/callback来访问com.bluelight.demo.web.CallbackServlet类了。



bluelightcode030.png
我们运行,右击bluelight->Run As->Run Server,然后Finish。



bluelightcode040.png
1、在后面添加callback,回车。
2、出现Null异常,说明已经成功调用了类,只是没有传参数。





那我们如何添加一个访问类地址呢?
bluelightcode050.png
我们复制,访着实现一个能使用calltest访问的地址。





bluelightcode060.png
重新运行,然后访问http://localhost:8080/demo/calltest,成功调用了类文件。
这里还有一种是jsp,可以直接放到WebContent目录里,直接访问文件名就可以,不需要做映射。




三、config.properties(微信公众号appID、appsecret、taken设置)
bluelightcode070.png
双击config.properties,打开后appID、appsecret、taken都是空的,我们要复制进去。



bluelightcode080.png
登陆公众号开发测试网址:
http://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index
直接复制appID、appsecret填写,URL是我们之后要教大家申请的服务器地址,taken自定义一个就可以了。



四、CallbackServlet.java(入口类讲解)
bluelightcode090.png
打开类,主要看到三个类:doGet、doPost、out函数。


bluelightcode100.png
在这里的doGet函数,基本不做事,只接收到传来的值,然后直接就返回空的值回去了,如果验证不通过就返回错误而以。



bluelightcode110.png
doPost涵数,多了解决xml,然后使用CallbackService业务类进行处理(这才是关键的地方),然后调用out函数才返回给微信。




bluelightcode120.png
out函数,使用了Writer类,然后输出返回,这样微信就能收到啦。




五、CallbackService.java(微信消息业务类讲解)
bluelightcode130.png
在入口类的doPost涵数里,调用了这个业务类,那我们来一一分析它。
这个类就只有一个事件处理函数handle


[Java] 纯文本查看 复制代码
package com.bluelight.demo.service;

import java.util.Map;

import org.apache.commons.codec.binary.Base64;

import com.bluelight.demo.api.DeviceApi;
import com.bluelight.demo.api.MpApi;
import com.bluelight.demo.consts.MsgType;
import com.bluelight.demo.consts.XmlResp;
import com.bluelight.demo.mock.DBMock;
import com.bluelight.demo.protocol.BlueLight;
import com.bluelight.demo.protocol.BlueLight.CmdId;

/**
 * 回调业务处理
 */
public class CallbackService {

        // 自定义菜单中的key值
        public static final String V1001_LIGHT_ON = "V1001_LIGHT_ON";//点灯
        public static final String V1002_LIGHT_OFF = "V1002_LIGHT_OFF";//灭灯
        
        public String handle(Map<String, String> reqMap) throws Exception {
                String msgType = reqMap.get("MsgType");
                String fromUser = reqMap.get("FromUserName");
                String toUser = reqMap.get("ToUserName");

                // 针对不同类型的消息和事件进行处理

                // 文本消息
                if (MsgType.TEXT.equals(msgType)) {
                        // 可以在此处进行关键字自动回复
                        String content = "收到文本消息:" + reqMap.get("Content");
                        return XmlResp.buildText(fromUser, toUser, content);
                }
                
                // 基础事件推送
                if (MsgType.EVENT.equals(msgType)) {
                        String event = reqMap.get("Event");
                        // 关注公众号
                        if (MsgType.Event.SUBSCRIBE.equals(event)) {
                                // 回复欢迎语
                                return XmlResp.buildText(fromUser, toUser, "欢迎关注蓝牙灯泡demo测试公众号!");
                        }
                        // 菜单点击事件
                        if (MsgType.Event.CLICK.equals(event)) {
                                // 根据key值判断点击的哪个菜单
                                String eventKey = reqMap.get("EventKey");
                                // 点灯/灭灯
                                if (V1001_LIGHT_ON.equals(eventKey) 
                                                || V1002_LIGHT_OFF.equals(eventKey)) {
                                        //是否点灯操作
                                        boolean open = V1001_LIGHT_ON.equals(eventKey);

                                        // 根据 fromUserName 获取绑定的信息
                                        Map<String, String> boundInfo = DBMock.queryBoundInfo(fromUser);

                                        // 未绑定
                                        if (boundInfo == null) {
                                                return XmlResp.buildText(fromUser, toUser, "未绑定");
                                        }

                                        String deviceType = boundInfo.get("deviceType");
                                        String deviceID = boundInfo.get("deviceID");
                                        String openID = boundInfo.get("openID");
                                        
                                        // 构造设备消息
                                        CmdId cmdId = open ? BlueLight.CmdId.OPEN_LIGHT_PUSH : BlueLight.CmdId.CLOSE_LIGHT_PUSH;
                                        byte[] respRaw = BlueLight.build(cmdId, null, (short)0).toBytes();
                                        // Base64编码
                                        final String content = Base64.encodeBase64String(respRaw);
                                        
                                        // 推送消息给设备
                                        DeviceApi.transMsg(deviceType, deviceID, openID, content);
                                        
                                        // 回复
                                        boolean debug = true;
                                        if(debug){
                                                // 返回调试信息
                                                String debugText = "已发送" + (open ? "点灯" : "灭灯") + "消息:" + "deviceID为" + deviceID + ",设备消息为" + content;
                                                return XmlResp.buildText(fromUser, toUser, debugText);
                                        }else{
                                                return "";
                                        }
                                }
                        }
                }

                // 设备消息或事件
                if (MsgType.DEVICE_EVENT.equals(msgType)
                                || MsgType.DEVICE_TEXT.equals(msgType)) {
                        String reqContent = reqMap.get("Content");
                        String deviceType = reqMap.get("DeviceType");
                        String deviceID = reqMap.get("DeviceID");
                        String sessionID = reqMap.get("SessionID");
                        final String openID = reqMap.get("OpenID");
                        // 设备事件推送
                        if (MsgType.DEVICE_EVENT.equals(msgType)) {
                                String event = reqMap.get("Event");
                                // 绑定/解绑事件
                                if (MsgType.DeviceEvent.BIND.equals(event)
                                                || MsgType.DeviceEvent.UNBIND.equals(event)) {
                                        // 存储用户和设备的绑定关系
                                        if(MsgType.DeviceEvent.BIND.equals(event)){
                                                DBMock.saveBoundInfo(reqMap);
                                        }else{
                                                DBMock.removeBoundInfo(reqMap.get("FromUserName"));
                                        }
                                        // 设备绑定/解绑事件可以回复空包体
                                        return "";
                                }
                        }
                        // 收到设备消息
                        if (MsgType.DEVICE_TEXT.equals(msgType)) {
                                // Base64解码
                                byte[] reqRaw = Base64.decodeBase64(reqContent);
                                // 反序列化
                                BlueLight lightReq = BlueLight.parse(reqRaw);
                                
                                // 逻辑处理
                                // demo中 推送消息给用户微信
                                String reqText = lightReq.body;
                                System.out.println("recv text:" + reqText);
                                String transText = "收到设备发送的数据:";
                                
                                byte[] reqTextRaw = reqText.getBytes("UTF-8");
                                if (reqTextRaw.length > 0 && reqTextRaw[reqTextRaw.length - 1] == 0) {
                                        // 推送给微信用户的内容去掉末尾的反斜杠零'\0'
                                        transText = transText + new String(reqTextRaw, 0, reqTextRaw.length - 1, "UTF-8");
                                } else{
                                        transText = transText + reqText;
                                }
                                
                                // 推送文本消息给微信
                                MpApi.customSendText(openID, transText);

                                // demo中 回复 收到的内容给设备
                                BlueLight lightResp = BlueLight.build(BlueLight.CmdId.SEND_TEXT_RESP, reqText, lightReq.head.seq); 
                                // 序列化
                                byte[] respRaw = lightResp.toBytes();
                                // Base64编码
                                String respCon = Base64.encodeBase64String(respRaw);
                                
                                // 设备消息接口必须回复符合协议的xml
                                return XmlResp.buildDeviceText(toUser, fromUser, deviceType, deviceID, respCon, sessionID);
                        }
                }

                // 未处理的情况返回空字符串
                return "";
        }
}


代码主要针对不同类型的消息,进行处理,如TEXT,EVENT,DEVICE_EVENT,DEVICE_TEXT。
TEXT是纯文本发过来,含表情。
EVENT是关注公众号,取消公众号,菜单点击等等,
DEVICE_EVENT是硬件的消息,DEVICE_TEXT就是硬件发送过来的文本(一般用文本交互就可以了)



bluelightcode140.png
在菜单点击事件里,实现了开和关,这里获取硬件的信息,前提是先扫二维码绑定,这个之后讲硬件时会讲到的。



bluelightcode150.png
在设备事件里,如果是绑定事件和解绑事件,就进行临时的保存和删除。



bluelightcode170.png
这里处理收到设备的信息处理。




[Java] 纯文本查看 复制代码
// 文本消息
                if (MsgType.TEXT.equals(msgType)) {
                        // 可以在此处进行关键字自动回复
                        String content = "收到文本消息:" + reqMap.get("Content");
if(reqMap.get("Content").equals("你好")){
        content = "你也好,你全家都好。";
}
                        return XmlResp.buildText(fromUser, toUser, content);
                }

这里我们做一下修改,添加一段代码,如果用户发送“你好”两字,那么我直接回复他:你也好,你全家都好。
if(content.equals("你好")){
content = "你也好,你全家都好。";
}





六、Tools.java(操作微信API类讲解)
bluelightcode180.png
Tools.java共有main、createQrByDeviceId、createQrImage、device_Auth、createMenu等5个函数。
分别为主函数、建立二维码、生成图片、授权设备、建立菜单。
这里我们只跳用建立菜单,二维码和授权,之后在说硬件的时候再教大家。


[Java] 纯文本查看 复制代码
// 文本消息
                if (MsgType.TEXT.equals(msgType)) {
                        // 可以在此处进行关键字自动回复
                        String content = "收到文本消息:" + reqMap.get("Content");
                        if(reqMap.get("Content").equals("你好")){
                                content = "你也好,你全家都好。";
                        }
                        if(reqMap.get("Content").equals("菜单") ){
                                Tools.createMenu();//建立菜单
                        }
                        return XmlResp.buildText(fromUser, toUser, content);
                }

跟上篇一样,用户发送菜单二字,我们就调用并生成菜单
提醒:(菜单生成微信要返回主界面,再进一次微信,同时设置第二次有时要24小时内才能生效)
但这里完成,经过小编测试,也还是不成功,原因是因为当前微信的demo不支持https请求(也不知道为什么微信demo自己不调试好),那我们再改改按下一个步聚来做就可以了。




七、支持Https的POST(默认DEMO不支持,修改代码)
bluelightcode190.png
我们要在这里添加二个文件,原本是没有的。



bluelightcode200.png
添加进去,SSLClient.java、MyX509TrustManager.java这两个文件就是实现https的请求的(修改后的DEMO在最后面提供给大家下载的)




bluelightcode210.png
我们还需要在http请求的地方调用SSLClient类,如上图,我们在executeGet、executePost添加了一段代码。
if( url.indexOf("https")>=0 ){
        httpclient =new SSLClient();
}else{
        httpclient = new DefaultHttpClient();
}
如果是https那么就自动请求ssl,实现可以请求https了。




八、JSP文件调用类文件。
bluelightcode220.png
右击WebContent文件-》New->JSP File,新建一个jsp文件,取名为test.jsp,然后点击finish。



bluelightcode230.png

自动生成jsp文件,然后运行。



bluelightcode240.png
网址后面加test.jsp,然后回车,就能看到白白的页面,访问成功。



bluelightcode250.png
[Java] 纯文本查看 复制代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="com.bluelight.tools.Tools"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
调用类函数的方法:
<%
            Tools ts= new Tools();
            ts.createMenu();
    %>
</body>
</html>

这时再修改一个这个文件的代码如上图,这样就可以成功调用类文件了,但不建议这么调用不正规,只是方便而以。

bluelightcode260.png
再运行,输出如下信息,说明成功!



九、打包成War文件。
bluelightcode270.png
开始导出war文件。


bluelightcode280.png
导出一个文件名,保存就能成功导出war文件,之后就可以上传到服务器了。



十、总结。
原来的DEMO不支持https请求,也没有jsp文件,这些都是要自己建立的。
经过对微信Demo的源代码分析、修改、调式,那么我们这一课节就完成了。
附源代码下载:http://pan.baidu.com/s/1skSC9jf



关注@智能创客  微信:znck007(打造DIY创客平台)









回复

使用道具 举报

0

主题

1

帖子

6

积分

新手上路

Rank: 1

积分
6
发表于 2016-6-12 17:11:27 | 显示全部楼层
看到这里有点蒙
回复 支持 反对

使用道具 举报

0

主题

0

帖子

16

积分

新手上路

Rank: 1

积分
16
发表于 2016-6-30 03:45:15 | 显示全部楼层


dddddddddddddd
回复 支持 反对

使用道具 举报

0

主题

1

帖子

27

积分

新手上路

Rank: 1

积分
27
发表于 2016-8-31 10:36:27 | 显示全部楼层
好!谢谢!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|小黑屋|手机版|智能创客 ( 桂ICP备14000828号

GMT+8, 2024-3-28 17:48 , Processed in 0.132446 second(s), 33 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表