申请测试账号
作为开发者个人能够申请的是订阅号,订阅号仅仅开放了基础接口,包含接收用户消息、向用户回复消息以及接受事件(事件推送有关注或取消关注、扫描带参数二维码(生成此类二维码需要高级接口)、上报地理位置(普通订阅号不支持)、自定义菜单(普通订阅号不支持)点击)推送三种接口,但高级点的功能如自定义菜单、语音识别、客服接口、OAuth2.0网页授权、获取用户地理位置信息等等均需要服务号才支持,其中认证了的订阅号支持自定义菜单。为了方便开发人员了解和学习腾讯公司的这些接口,如任何平台公司那样,腾讯公司去年晚点的时候终于开放了测试账号的申请。只要有微信订阅号的用户都可以申请(服务号应该也可以吧,不过没见过服务号后台长啥样,不做评论)。
申请方式简单、直接,进入到微信后台(https://mp.weixin.qq.com)后在最新版(截止2014年7月6日)的后台左侧最下面有一个“开发者中心”的链接,点击后能找到一个“接口测试申请系统 点击进入”的链接,点击进入后按照腾讯公司的想到申请即可,这里不做赘述。

申请成功登陆后的样子如下,这里你就能看到,滚动页面还能看到一个二维码,通过微信扫描这个二维码既可以关注这个测试账号,最多支持20个测试用户,关注成功后在微信“订阅号”文件夹里会多出一个叫做“微信公众平台测试号”的账号,注意虽然是在“订阅号”文件夹,但是具有所有服务号的功能:

基础框架搭建
为了接下来的工作,这里我们先搭建几个关键的类以及相应的处理框架,以方便后续添加更多功能支持。
IncomingMsg:用户发送来的消息类,包含了各个关键字段信息;
WeChatNews: 回复图文并茂新闻时的新闻类;
IncomingMsg类代码如下,12个字段,包含了各种消息类型的绝大部分字段信息:
public class IncomingMsg{
public String toUserName;
public String fromUserName;
public String msgType;
public String picURL;
public String mediaID;
public String locationX;
public String locationY;
public String URL;
public String content;
public String event;
public String eventKey;
public String recognition;
public IncomingMsg(){}
public IncomingMsg(String tUN, String fUN, String mT, String pU, String mI, String lX, String lY, String u, String c, String e, String eK, String r){
this.toUserName = tUN;
this.fromUserName = fUN;
this.msgType = mT;
this.picURL = pU;
this.mediaID = mI;
this.locationX = lX;
this.locationY = lY;
this.URL = u;
this.content = c;
this.event = e;
this.eventKey = eK;
this.recognition = r;
}
}WeChatNews类的定义代码如下,包含了一条新闻的详细定义信息:
public class WeChatNews{
public String title;
public String description;
public String picUrl;
public String url;
public WeChatNews(){}
public WeChatNews(String t, String d, String p, String u){
this.title = t;
this.description = d;
this.picUrl = p;
this.url = u;
}
}接下来,在doPost方法里,我们将晚上上篇博文里的XML解析代码,使其能够解析任何类型的微信XML文,修改后的doPost方法如下:
global static void doPost(){
//Receive message from user;
RestRequest req = RestContext.request;
RestResponse res = RestContext.response;
string strMsg = req.requestBody.toString();
System.debug('Request Contents' + strMsg);
XmlStreamReader reader = new XmlStreamReader(strMsg);
String toUserName = '';
String fromUserName = '';
String msgType = '';
String picURL = '';
String mediaID = '';
String locationX = '';
String locationY = '';
String URL = '';
String content = '';
String msgID = '';
String event = '';
String eventKey = '';
String recognition = '';
while(reader.hasNext()){
if(reader.getLocalName() == 'ToUserName'){
reader.next();
if(String.isNotBlank(reader.getText())){
toUserName = reader.getText();
}
}
else if(reader.getLocalName() == 'FromUserName'){
reader.next();
if(String.isNotBlank(reader.getText())){
fromUserName = reader.getText();
}
}
else if(reader.getLocalName() == 'MsgType'){
reader.next();
if(String.isNotBlank(reader.getText())){
msgType = reader.getText();
}
}
else if(reader.getLocalName() == 'PicURL'){
reader.next();
if(String.isNotBlank(reader.getText())){
picURL = reader.getText();
}
}
else if(reader.getLocalName() == 'MediaId'){
reader.next();
if(String.isNotBlank(reader.getText())){
mediaID = reader.getText();
}
}
else if(reader.getLocalName() == 'Location_X'){
reader.next();
if(String.isNotBlank(reader.getText())){
locationX = reader.getText();
}
}
else if(reader.getLocalName() == 'Location_Y'){
reader.next();
if(String.isNotBlank(reader.getText())){
locationY = reader.getText();
}
}
else if(reader.getLocalName() == 'Url'){
reader.next();
if(String.isNotBlank(reader.getText())){
URL = reader.getText();
}
}
else if(reader.getLocalName() == 'MsgId'){
reader.next();
if(String.isNotBlank(reader.getText())){
msgID = reader.getText();
}
}
else if(reader.getLocalName() == 'Content'){
reader.next();
if(String.isNotBlank(reader.getText())){
content = reader.getText();
}
}
else if(reader.getLocalName() == 'Event'){
reader.next();
if(String.isNotBlank(reader.getText())){
event = reader.getText();
}
}
else if(reader.getLocalName() == 'EventKey'){
reader.next();
if(String.isNotBlank(reader.getText())){
eventKey = reader.getText();
}
}
else if(reader.getLocalName() == 'Recognition'){
reader.next();
if(String.isNotBlank(reader.getText())){
recognition = read

