Force.com微信开发系列(三)申请测试账号及回复图文消息

时间:2023-02-25 17:50:19

Force.com除了简单的文本消息回复外,还能回复图文并茂的消息、能回复音乐或者视频、能对用户发来的语音进行识别、能够搜集用户的地理位置信息并提供相应的内容或服务等,本文将对这些技能一一展开说明,在此之前首先要介绍如何申请一个具有所有服务号接口功能的测试账号(尽管对于图文消息回复这并不是必须的)。

申请测试账号

作为开发者个人能够申请的是订阅号,订阅号仅仅开放了基础接口,包含接收用户消息、向用户回复消息以及接受事件(事件推送有关注或取消关注、扫描带参数二维码(生成此类二维码需要高级接口)、上报地理位置(普通订阅号不支持)、自定义菜单(普通订阅号不支持)点击)推送三种接口,但高级点的功能如自定义菜单、语音识别、客服接口、OAuth2.0网页授权、获取用户地理位置信息等等均需要服务号才支持,其中认证了的订阅号支持自定义菜单。为了方便开发人员了解和学习腾讯公司的这些接口,如任何平台公司那样,腾讯公司去年晚点的时候终于开放了测试账号的申请。只要有微信订阅号的用户都可以申请(服务号应该也可以吧,不过没见过服务号后台长啥样,不做评论)。

申请方式简单、直接,进入到微信后台(https://mp.weixin.qq.com)后在最新版(截止2014年7月6日)的后台左侧最下面有一个“开发者中心”的链接,点击后能找到一个“接口测试申请系统 点击进入”的链接,点击进入后按照腾讯公司的想到申请即可,这里不做赘述。

Force.com微信开发系列(三)申请测试账号及回复图文消息

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

Force.com微信开发系列(三)申请测试账号及回复图文消息          Force.com微信开发系列(三)申请测试账号及回复图文消息

基础框架搭建

为了接下来的工作,这里我们先搭建几个关键的类以及相应的处理框架,以方便后续添加更多功能支持。

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 = reader.getText();
}
}
reader.next();
}
IncomingMsg inMsg = new IncomingMsg(toUserName, fromUserName, msgType, picURL, mediaID, locationX, locationY, URL, content, event, eventKey, recognition );
}

该方法里,我们对所有类型微信消息XML文里的字段进行了解析,并通过解析回来的值初始化了IncomingMsg对象,接下来,我们将通过传递这个对象调用不同的方法完成各种任务。接下来我们在上述doPost方法的最后加上以下代码:

 String rtnMsg = '';
//回复消息 if(msgType.equals('text')){
rtnMsg = handleText(inMsg);
}
RestContext.response.addHeader('Content-Type', 'text/plain');
RestContext.response.responseBody = Blob.valueOf(rtnMsg);

这段代码里首先定义了一个存储返回XML文的String字符串,接着判断如果用户发来的消息类型是文本类型,则调用一个handleText的方法来处理回复信息,这里传递给handleText方法的对象正是我们前面定义的IncomingMsg对象,关于该方法的细节我们下一小节再介绍,这里成功拿到该方法的返回字符串后,通过RestContext即可将XML文消息返回给腾讯微信,进一步返回给发送消息的用户。

发送图文方法handleText详解

接下来我们将介绍如何回复图文消息。留意,图文消息回复并不需要申请测试账号,普通订阅号即可。下面是该方法的全部代码:

 private static String handleText(IncomingMsg msg){
String keyword = msg.content;
String strReply;
String strResult;
if(keyword.equals('文本')){
strReply = '这是个文本消息';
strResult = composeTextReply(msg, strReply);
}
else if(keyword.equals('图文') || keyword.equals('单图文')){
WeChatNews news = new WeChatNews('苹果WWDC2014召开在即', '2014 年似乎将成为又一个“苹果之年”,热爱和不那么热爱苹果的人都对它的一举一动保持着关注和揣测——以下是苹果 WWDC 2014 的13大看点:', 'http://a.36krcnd.com/photo/2014/4e3ae0dac4884bb91934a689b72f8f8b.png', 'http://www.36kr.com/p/212479.html');
List<WeChatNews> newsList = new List<WeChatNews>();
newsList.add(news);
strResult = composeNewsReply(msg, newsList);
}
else if(keyword.equals('多图文')){
WeChatNews news1 = new WeChatNews('苹果WWDC2014召开在即', '2014年似乎将成为又一个苹果之年,热爱和不那么热爱苹果的人都对它的一举一动保持着关注和揣测——以下是苹果 WWDC 2014 的13大看点:', 'http://a.36krcnd.com/photo/2014/4e3ae0dac4884bb91934a689b72f8f8b.png', 'http://www.36kr.com/p/212479.html');
WeChatNews news2 = new WeChatNews('Facebook CEO 马克·扎克伯格再做慈善,为湾区学校捐赠 1.2 亿美元', '据 re/code消息,Facebook CEO 马克·扎克伯格与妻子Priscilla Cha (中文名陈慧娴) 计划向湾区学校捐赠 1.2 亿美元。', 'http://a.36krcnd.com/photo/2014/e64d647389bfda39131e12fa9d606bb6.jpg', 'http://www.36kr.com/p/212476.html');
WeChatNews news3 = new WeChatNews('Nokia收购Siri的同门师弟Desti,为自家地图业务HERE融入更多人工智能', 'Nokia最近收购了一家地图公司Desti,来补强自家的地图业务HERE。', 'http://a.36krcnd.com/photo/2014/25490e2b8e63ced9586f0a432eebb972.jpg', 'http://www.36kr.com/p/212484.html');
List<WeChatNews> newsList = new List<WeChatNews>();
newsList.add(news1);
newsList.add(news2);
newsList.add(news3);
strResult = composeNewsReply(msg, newsList);
}
else if(keyword.equals('音乐')){
Map<String, String> music = new Map<String, String>();
music.put('title', '爱你的宿命');
music.put('description', '张信哲');
music.put('musicUrl', 'http://zhangmenshiting.baidu.com/data2/music/119826740/1197655931401552061128.mp3?xcode=80587c819993d49621a8dce05e5bb8c9e36664380262dc7e&song_id=119765593');
music.put('musicHQUrl', 'http://zhangmenshiting.baidu.com/data2/music/119826740/1197655931401552061128.mp3?xcode=80587c819993d49621a8dce05e5bb8c9e36664380262dc7e&song_id=119765593');
strResult = composeMusicReply(msg, music);
}
return strResult;
}

代码的思路应该来说比较直接,从第4行的if开始判断用户发送过来的文本是什么,根据不同的关键字来确定不同的返回内容,第一个if里将返回给用户单图文信息,这里先构造了一个WeChatNews数组,当然数组里只有一个WeChatNews对象,将这个数组交给composeNewsReply来完成最终的XML文构建;第一个else if也很类似,只不过这里的WeChatNews数组里有三条新闻,关于composeNewsReply方法的细节我们稍后介绍;最后一个else if里展示了如何回复音乐,这里我们构建了一个Map对象存储音乐的详情,并调用composeMusicReply方法来完成最终的XML文构建,同样该方法的细节稍后就会介绍到。

上面的思路应该来说还是比较清楚的,接下来介绍composeNewsReply方法的全部代码:

 private static String composeNewsReply(IncomingMsg msg, List<WeChatNews> newsList){
String strNews = '';
String newsTpl = '<item><Title><![CDATA[{0}]]></Title><Description><![CDATA[{1}]]></Description><PicUrl><![CDATA[{2}]]></PicUrl><Url><![CDATA[{3}]]></Url></item>';
for(WeChatNews news : newsList){
String[] arguments = new String[]{news.title, news.description, news.picUrl, news.url};
strNews += String.format(newsTpl, arguments);
}
String strTmp = '<xml><ToUserName><![CDATA[{0}]]></ToUserName><FromUserName><![CDATA[{1}]]></FromUserName><CreateTime>1234567890</CreateTime><MsgType><![CDATA[news]]></MsgType><ArticleCount><![CDATA[{2}]]></ArticleCount><Articles>' + strNews + '</Articles></xml>';
String[] arguments = new String[]{msg.fromUserName, msg.toUserName, String.valueOf(newsList.size())};
String results = String.format(strTmp, arguments);
return results;
}

了解该方法代码前先要了解回复图文信息的XML格式,关于此点可以参照腾讯公司链接:回复图文消息 ,与前文介绍到的普通文本消息大同小异,可以留意到里面有个ArticleCount字段用来指定回复的消息里能有几条图文新闻,最大是10,超过10则会无法响应;另外Article节点下方每一个item均是一条图文消息。为此,上述代码的第3行先构造一个每条新闻的模板,接着从第4行开始轮询新闻列表里的每一条新闻,并构造相应的XML文。从第8行开始构造整个图文回复的字符串模板,并在第9、10行通过相应参数将模板转换为最终的XML字符串。

再接下来介绍composeMusicReply,该方法的全部代码如下:


 private static String composeMusicReply(IncomingMsg msg, Map<String, String> music){
String strTitle = music.get('title');
String strDesc = music.get('description');
String strURL = music.get('musicUrl');
String strHQURL = music.get('musicHQUrl');
String musicTpl = '<xml><ToUserName><![CDATA[{0}]]></ToUserName><FromUserName><![CDATA[{1}]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[music]]></MsgType><Music><Title><![CDATA[{2}]]></Title><Description><![CDATA[{3}]]></Description><MusicUrl><![CDATA[{4}]]></MusicUrl><HQMusicUrl><![CDATA[{5}]]></HQMusicUrl></Music></xml>';
String[] arguments = new String[]{msg.fromUserName, msg.toUserName, strTitle, strDesc, strURL, strHQURL};
String results = String.format(musicTpl, arguments);
return results;
}
同样了解该方法要首先了解回复音乐信息的XML格式,可以参照腾讯公司链接:回复音乐消息,上面代码与前面方法比较类似,就不再赘述。(这里的Map对象也许有点多余,可以考虑是否可以和回复视频的方法整合到一起,否则不需要额外的Map对象开销,直接将标题、描述、链接等信息传给composeMusicReply方法即可)。

运行效果

完成后直接保存代码便可立即生效,回复图文、多图文、音乐的运行效果分别如下:

Force.com微信开发系列(三)申请测试账号及回复图文消息          Force.com微信开发系列(三)申请测试账号及回复图文消息          Force.com微信开发系列(三)申请测试账号及回复图文消息

Force.com微信开发系列(三)申请测试账号及回复图文消息的更多相关文章

  1. Force&period;com微信开发系列(五)自定义菜单进阶及语音识别

    在上文里我们介绍了如何通过Force.com平台里为微信账号添加自定义菜单,本文里我们将进一步介绍如何查询菜单以及删除菜单的相关知识,最后会介绍微信平台如何进行语音识别的相关技术. 查询菜单 与创建菜 ...

  2. Force&period;com微信开发系列(四)申请Access Token及自定义菜单之创建菜单

    在微信接口开发中,许多服务的使用都离不开Access Token,Access Token相当于打开这些服务的钥匙,正常情况下会在7200秒内失效,重复获取将导致上次获取的Token失效,本文将首先介 ...

  3. Force&period;com微信开发系列(七)OAuth2&period;0网页授权

    OAuth是一个开放协议,允许用户让第三方应用以安全且标准的方式获取该用户在某一网站上存储的私密资源(如用户个人信息.照片.视频.联系人列表),而无须将用户名和密码提供给第三方应用.本文将详细介绍OA ...

  4. Force&period;com微信开发系列(六)客服接口

    当用户主动发消息给微信公众账号的时候(包括发送信息.点击自定义菜单click事件.订阅事件.扫描二维码事件.支付成功事件.用户维权),微信将会把消息数据推送给开发者,开发者在一段时间内(目前为48小时 ...

  5. Force&period;com微信开发系列(一) 后台配置

    为寻找国内免费云资源作为微信后台,花了一天时间试用SinaAppEngine(SAE),调试太不方便用户体验差.新浪作为媒体公司技术功底经不起考验,亚马逊能推出AWS,新浪还不行!更好选项是百度Bai ...

  6. Force&period;com微信开发系列(二)用户消息处理

    Force.com是国际知名的云平台公司,成功配置好Force.com作为微信公开号的服务端后,接下来需要的任务是处理用户发送的消息.当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML ...

  7. Force&period;com微信开发系列(八)生成带参数的二维码

    为了满足用户渠道推广分析的需要,公众平台提供了生成带二维码的接口.使用该接口可以获得多个带不同场景值的二维码,用户扫描后,公众号可以接收到事件推送.目前有两种类型的二维码,分别是临时二维码和永久二维码 ...

  8. asp&period;net微信开发第十篇----使用百度编辑器编辑图文消息,上传图片、微信视频

    经过几天的资料收集,终于完成了该编辑器的图片上传,视频插入功能,视频插入功能主要借用了该编辑器的插入iframe功能,如原始插件图: 修改后的插件图如下(其中我隐藏掉了一些不需要使用的插件功能): 配 ...

  9. 《C&num;微信开发系列(4)-接收 &sol; 返回文本消息》

    4.0接收 / 返回文本消息 ①接收/返回文本消息原理说明 当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上,着手开发之前先行阅读微信公众平台接收普通消息 ...

随机推荐

  1. &period;NET WinForm画树叶小程序

    看了一片文章(http://keleyi.com/a/bjac/nurox416.htm),是使用分型画树叶,代码是Java的,因为Java很久没弄了,改用C#实现,下载地址: 画树叶小程序下载 核心 ...

  2. 搭建网站 discuzx ecshop php

    1.http://www.comsenz.com/downloads/install/discuzx下载

  3. HDU5317

    题意:定义一个数K,最小质因数形式为K = a*b*c形式(如12 = 2*2*3),相同只取一个(所以12只能取2,3两个,既F[12]=2)给L,R区间,找出区间内最大的F[x](L<=x& ...

  4. Spring:AOP

    摘要 本文内容为我在网上搜集Spring AOP资料的汇总.摘抄. AOP是一种编程思想,其对不同对象进行了横向的抽象,将不同对象的.和主流程无关的公共逻辑抽象出来以方便维护.AOP的实现基础为AOP ...

  5. CF747F Igor and Interesting Numbers

    我佛了,这CF居然没有官方题解. 题意:给定k,t,求第k小的16进制数,满足每个数码的出现次数不超过t. 解: 每个数都有个出现次数限制,搞不倒.一开始想到了排序hash数位DP,不过写了写觉得不胜 ...

  6. STM8S ------ VCAP download

    There is a specific pin called vcap in stm8s mcu. I recommend this pin connects to a 1uF capacitor w ...

  7. abap调用代码块

    1:abap 调用代码块. *&---------------------------------------------------------------------* *& Re ...

  8. C语言实现随机生成0或1

    rand函数在产生随机数前,需要系统提供的生成伪随机数序列的种子,rand根据这个种子的值产生一系列随机数.如果系统提供的种子没有变化,每次调用rand函数生成的伪随机数序列都是一样的.srand(u ...

  9. 用DDE控制Word

    DDE(Dynamic Data Exchange),称为动态数据交换.用于进程间的通讯,看看他如何来和Word交互. 在System页签下有TDdeClientConv组件,拖一个放到界面上,然后我 ...

  10. jquery 实现table的行列选中效果改进

    行列都可以多选,也可对相应数据进行统计: 行选中效果 列选中效果