简介
AbleCloud打通了和微信的接入,实现了双方的云端对接,开启了微信硬件开发的全新模式。在该模式下,结合AbleCloud提供的jssdk,厂商可以在您的微信公众号里实现和native app几乎一样的智能硬件相关功能特性,并且保证足够的安全性。本文介绍连接微信公众平台mp和AbleCloud云平台的关键服务开发框架ac-weixin-server
。
基于ac-weixin-server,您只需要关注常规的公众号开发内容,所有与AbleCloud云端交互的逻辑均已在该框架中完成,对设备的授权、控制等操作,直接在HTML页面中调用AbleCloud提供的jssdk即可。jssdk的接口说明请参见jssdk手册。
架构框图
AbleCloud实现的和微信云端对接,其架构如下:
在整个架构中,厂商的公众号开发人员只需要根据厂商自己的需求,扩展高亮部分ac-weixin-server
的功能开发便可,图中其它模块不用太关注。
功能列表
整个ac-weixin-server
的主要功能提供http服务器功能,提供如下几个功能:
- 提供Web Application:提供静态网页、js、资源的web服务功能。
- 处理公众平台的验证请求:对微信公众平台发过来的公众号提供验证。
- 用户OAuth认证:目前提供了scope为snsapi_base的Oauth认证功能。
- 公众号Access Token的管理:提供公众号Access Token的获取以及刷新功能。
- 公众号JS API Ticket的管理:提供公众号JS API Ticket的获取以及刷新功能。
- 提供Servlet Handler:提供对微信公众平台推送的各类消息进行动态处理功能。
- 其它实用工具类接口:提供HttpUtil,能方便的发送GET、POST请求等。
框架说明
由于ac-weixin-server
进行了高度的抽象,厂商只需要继承抽象类ACMPService
,实现处理函数即可。通常情况下,在函数handleMsg
内部,根据已经解析好的参数reqMap中的MsgType,做出不同的处理逻辑,具体请参见后面的demo。
主体框架类
public abstract class ACMPService {
/**
* 厂商为了开发自己的公众号,只需要实现该抽象方法即可。
*
* @param reqMap 已经由框架解析成key-value对的req
* @param req 原生req,如果无特殊需求,通常情况下可以不使用该参数,直接用第一个参数reqMap即可
* @param resp 处理请求后的response
* @return String 返回微信公众平台要求的xml文档格式字符串,可参考ACDefaultMPService的代码。
* @throws Exception
*/
public abstract String handleMsg(Map<String, String> reqMap,
HttpServletRequest req,
HttpServletResponse resp) throws Exception;
/**
* 允许开发者通过WebAppContext扩展框架定义的Servlet服务能力。这些扩展的Servlet的位于根路径"/"下。
* @param webApp Servelet容器。
*/
public void extendResource(WebAppContext webApp);
/**
* 设置AblceCloud远程服务的访问代理。
* @param ac AbleCloud远程服务的访问代理。
*/
public void setACCloudAgent(AC ac);
/**
* 设置AblceCloud远程服务的访问代理。
* @return 一个AC对象,是AbleCloud远程服务的访问代理。
*/
public AC getACCloudAgent();
/**
* 同步AbleCloud平台及微信硬件平台记录的用户-设备绑定信息。同时检查指定设备的在线状态。
* @details 框架接收到微信硬件平台推送的subscribe_status/unsubscribe_status事件时(比如用户打开或关闭公众号主界面时),会调用本方法同步两个平台之间的信息。
* 开发者也可根据实际需求主动调用该方法执行数据同步(比如处理蓝牙设备绑定关系的同步)。
* @param fromUser 待检查的用户的微信OpenID。
* @param physicalIdOfStatus 需要检查其在线状态的设备的物理ID。
* @return 返回true表示设备在线,否则表示设备不在线。
*/
public boolean syncBindings(String fromUser, String physicalIdOfStatus);
}
获取Access Token
ac-weixin-server
提供了公众号Access Token的管理功能。在您开发公众号的过程,如果需要用到access token,只需调用utils
包中AccessTokenKeeper
的静态方法getTokenStr
即可拿到公众号的Access Token,不用关注繁琐的获取、刷新过程。
public class AccessTokenKeeper {
public static String getTokenStr();
}
获取JS API Ticket
ac-weixin-server
提供了公众号微信JS API Ticket的管理功能。在您开发公众号的过程,如果需要用到JS API Ticket,只需调用utils
包中JsApiTicketKeeper
的静态方法getTicketStr
即可拿到公众号的JS API Ticket,不用关注繁琐的获取、刷新过程。
public class JsApiTicketKeeper {
public static String getTicketStr();
}
HttpUtil
为了方便主动向微信公众平台发送消息,封装了这个实用工具类:
public class HttpUtil {
/**
* 发送基本的GET请求
*
* @param url 目的地址url
* @return String GET请求返回结果content
*/
public static String executeGet(String url);
/**
* 发送GET请求
*
* @param url 目的地址url,该url的pattern中带有ACCESS_TOKEN,
* 在该函数内部会通过AccessTokenKeeper获取正确的token替换,
* 然后调用executeGet执行GET请求。
*/
public static String doGet(String url);
/**
* 发送基本的POST请求
*
* @param url 目的地址url
* @param body POST请求内容
* @return String POST请求返回结果
*/
public static String executePost(String url, String body);
/**
* 发送POST请求
* @param url 目的地址url,该url的pattern中带有ACCESS_TOKEN,
* 在该函数内部会通过AccessTokenKeeper获取正确的token替换,
* 然后调用executeGet执行GET请求。
*/
public static String doPost(String url, String body);
}
自定义Servlet
在继承抽象类ACMPService
、并实现其抽象方法handleMsg
的类中,厂商可以通过重载ACMPService::extendResource
方法来添加自定义的Servlet,实现对框架的扩展。代码示例如下:
/**
* 重载父类的 extendResource 方法,添加自定义的Servlet。这些扩展的Servlet位于根路径"/"下。
* @param webApp 添加扩展Servlet的容器。
*/
@Override
public void extendResource(WebAppContext webApp) {
AC ac = this.getACCloudAgent();
webApp.addServlet(new ServletHolder(new AirListServlet()), "/airlist");
webApp.addServlet(new ServletHolder(new AirCodeServlet(ac)), "/aircode");
}
网页授权并转向指定页面
本框架的Servlet类ACWXOauthServlet
封装了微信提供的网页授权功能。该Servlet的地址是:/weixin/oauth2
。
当提供redirect_url
参数时,可通过该Servlet实现完成微信用户网页授权并转向指定页面的功能。
如将公众号的某VIEW类型菜单项的URL设置为:http://www.example.com/weixin/oauth2?redirect_url=http://www.example.com/some_page.html
,那么用户点击该菜单打开微信客户端的浏览器后,
将首先跳转至微信的网页授权页面。完成授权后,浏览器将最终自动跳转至参数redirect_url
指定的页面地址。
在这个过程中,ACWXOauthServlet
将自动向cookies中添加如下三项键值对:
-
wxOpenId:是访问该页面的微信用户的OpenID。
-
acMajorDomain:是当前微信公众号所关联的AbleCloud开发者的信息:主域的名字。
-
acSubDomain:是当前微信公众号所关联的AbleCloud开发者的信息:子域的名字。
AirKiss页面
本框架封装了缺省的微信AirKiss页面(由Servlet类ACWXAirKissServlet
提供)。该页面的地址是:/weixin/airkiss
。
开发流程
基于ac-weixin-server
开发厂商自己的公众号服务,除了不用关注硬件和微信交互细节外,我们还提供了常规公众号开发的基础封装,如access token管理,微信公众平台推送过来的消息解析等功能。因此厂商开发自己的公众号将变得更加简单。
1、申请微信公众号
由于公众号属于各个厂商,因此,申请公众号这个步骤由厂商完成。申请好后,会拿到微信公众平台分配的appID和appsecret,如下图所示:
2、准备服务器
当前,AbleCloud暂时还未提供主机代理服务,因此需要厂商准备机器,并配置外网ip,最好申请一个域名。该服务器用来运行ac-weixin-server
。由于微信方的要求,现在该后台服务只能使用80端口。
注:后续AbleCloud提供主机代理服务后,厂商无需再准备服务器,厂商的公众号后台
ac-weixin-server
服务也运行在AbleCloud的云端。
3、扩展ac-weixin-server功能
ac-weixin-server
的发布库目录结构如下:
config目录下存放配置文件,lib目录下存放所有的jar文件,包括ac-weixin-server框架及其依赖包,继承ACMPService
,开发实现自己的handleMsg
编译成功后,也放入lib目录即可。start.cmd用于windows平台启动服务,start.sh用于linux平台启动服务。这里解释下webRoot目录,该目录用来存放公众号所需的html页面及其它静态资源,其结构大致如下:
4、编写html页面
在webRoot目录下,编写您所需的网页html或h5页面,如果要和已经接入AbleCloud平台的设备进行控制等功能,请在html页面中调用js目录下AbleCloud提供ac.js,该jssdk提供了和AbleCloud云端交互所需的丰富接口,具体参见jssdk手册。 当然,您可以为您的公众号编写除硬件相关页面之外的其它任意html页面。
5、修改配置文件
config目录下配置文件config.properties完整配置项如下,需要注意的是,配置项token后面在微信公众号接口配置信息时要用到。
app_id = wx37200xxxxxxxxxxxxxxxx
app_secret = a58001xxxxxxxxxxxxxxxxxxxxxxxxx
token = xxxxxx
host = 127.0.0.1
port = 80
major_domain = testwx
sub_domain = demo
developer_id = 2
access_key = 5a11d05exxxxxxxxxxxxxxxxxxxxxxxx
secret_key = 61a5edd9xxxxxxxxxxxxxxxxxxxxxxxx
router_addr = http://test.ablecloud.cn:5000
redirect_url_after_airkiss = http://www.xxx.com/xxx.html
servlet_context_path_prefix =
weixin_mp_message_handler_class = com.ablecloud.weixin.service.ACDefaultMPService
上述配置项中:
- app_id,app_secret,token和微信公众号相关。
- major_domain,sub_domain,developer_id,access_key,secret_key和AbleCloud相关,请登录AbleCloud的console查看。
- weixin_mp_message_handler_class是您自定义的微信公众号核心消息处理类的名字,继承自ACMPService。
- router_addr是AbleCloud云端服务的入口地址。"http://test.ablecloud.cn:5000"是测试环境的入口地址。
- redirect_url_after_airkiss是调用本框架的AirKiss页面并且配置成功时,浏览器自动跳转的目的页面地址。
- servlet_context_path_prefix是访问本框架的Servlet时URL的前缀。 该前缀可用在需要为本框架做反向代理的场景下。比如,服务器的80端口已经被其它应用使用,此时可设置本框架使用其它任意端口(如8001),而使用nginx等工具为本框架做反向代理。 假设规定URL路径匹配前缀/mp/的请求全部反向代理至本框架来处理,如请求"http://127.0.0.1/mp/weixin/airkiss"就是满足反向代理的访问,则可配置servlet_context_path_prefix的值为"/mp"。 注意,此处配置只是本框架的运行参数,真正实现反向代理需要对nginx等工具进行配置。
6、部署ac-weixin-server
当开发完消息处理handler,html页面后,便可以部署整个微信公众号后台服务。我们提供了启动脚本,部署变得非常简单。
windows平台
windows下在cmd中运行如下命令启动服务
start.cmd
linux平台
linux下在终端运行如下命令启动服务
sh start.sh
真正线上启动,需要用nohup等将服务放后台,如nohup sh start.sh &
,并且可能需要使用supervisor配合,防止进程异常退出。
7、修改公众号接口配置信息
在微信公众平台修改接口配置信息,如下图所示:
点击提交,正常情况下,会收到微信公众平台提示验证成功。如果验证失败,请查看log目录下的日志。
注:这里填写的token要和配置文件中的token一致。并且URL的URI部分(除去域名)必须是
/weixin/message
,域名部分则是您服务器所申请的域名。
8、创建公众号菜单
根据微信公众平台的要求,创建菜单即可,这里不做详述。
注:菜单中需要创建一个VIEW类型的菜单,用来激活设备之用,该菜单url的URI部分必须是
/weixin/airkiss
,域名部分则是您服务器所申请的域名。
demo
这里以一个非常简单的实例演示厂商如何扩展开发完整的公众账号。该demo在实现handleMsg接口时,处理了MsgType为event,并且具体的event为用户关注公众号消息subscribe,在收到此请求的时候发送欢迎语给用户。 你可以在handlMsg中处理任何微信公众平台的消息,如文本text,图片image,语音voice,视频video等,当然,你也可以处理任意的自定义菜单点击事件消息。一句话,所有微信公众平台推送过来的消息,你都能方便的进行处理。
新建工程
这里以Intellij为例简单说明,首先新建工程,然后修改工程属性配置,选择JDK为1.7和语言级别为7.0,如下图所示:
修改library,添加对ac-weixin-server框架的依赖,如下图所示(具体的依赖目录需要您根据存放框架lib库的地址不同而进行调整):
修改工程pom.xml配置
DemoServer的完整编译配置如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ablecloud.weixin.demo</groupId>
<artifactId>DemoServer</artifactId>
<version>1.0.0</version>
<properties>
<ablecloud.weixin.lib.dir>/home/chenpeng/IdeaProjects/ac-weixin-server/target/lib</ablecloud.weixin.lib.dir>
</properties>
<build>
<plugins>
<plugin>
<!--this plugin and dependency jars are used for testing-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>2.18.1</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
<compilerArguments>
<extdirs>${ablecloud.weixin.lib.dir}</extdirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>
其中绝大部分内容无需修改,您进需要修改配置项存放ac-weixin-server框架的lib库路径即可:
<properties>
<ablecloud.weixin.lib.dir>/home/chenpeng/IdeaProjects/ac-weixin-server/target/lib</ablecloud.weixin.lib.dir>
</properties>
编译工程
在终端运行命令mvn package
即可将DemoServer编译成功,编译后的jar包存放于工程主目录下的target/lib
路径下,这里为DemoServer-1.0.0.jar
。
运行公众号后端服务
- 将上步编译好的您公众号具体的处理逻辑jar包
DemoServer-1.0.0.jar
拷贝到AbleCloud发布的框架lib目录中; - 修改框架配置文件
config/config.properties
中的配置项weixin_mp_message_handler_class
为你具体的处理类名,这里是com.ablecloud.weixin.ACDemoMPService
; - 运行
sh start.sh
即可。
源码展示
package com.ablecloud.weixin;
import com.ablecloud.weixin.common.ACWXMsgType;
import com.ablecloud.weixin.common.ACWXXmlResp;
import com.ablecloud.weixin.service.ACMPService;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
public class ACDemoMPService extends ACMPService {
public String handleMsg(Map<String, String> reqMap,
HttpServletRequest req,
HttpServletResponse resp) throws Exception {
String msgType = reqMap.get("MsgType");
String fromUser = reqMap.get("FromUserName");
String toUser = reqMap.get("ToUserName");
String xmlResp;
switch (msgType) {
case ACWXMsgType.TEXT: {
break;
}
case ACWXMsgType.EVENT: {
String event = reqMap.get("Event");
switch (event) {
case ACWXMsgType.Event.SUBSCRIBE:
// handle subscribe msg
xmlResp = "欢迎关注AbleCloud智能硬件公众号,开启全新的微信硬件功能开发模式。<a href='http://docs.ablecloud.cn/sdk/js_sdk_manual/'>了解更多</a>";
return ACWXXmlResp.buildTextResp(fromUser, toUser, xmlResp);
}
break;
}
}
return "";
}
}
这么一个简单的demo实现,便完成了公众号后台的开发,当用户扫描设备二维码时,会自动关注您的公众号,您同时也给了用户一个热烈的欢迎辞。