Force.com微信开发系列申请测试账号及回复图文消息
Force.com除了简单的文本消息回复外,还能回复图文并茂的消息、能回复音乐或者视频、能对用户发来的语音进行识别、能够搜集用户的地理位置信息并提供相应的内容或服务等,本文将对这些技能一一展开说明,在此之前首先要介绍如何申请一个具有所有服务号接口功能的测试账号(尽管对于图文消息回复这并不是必须的)。
申请测试账号
作为开发者个人能够申请的是订阅号,订阅号仅仅开放了基础接口,包含接收用户消息、向用户回复消息以及接受事件(事件推送有关注或取消关注、扫描带参数二维码(生成此类二维码需要高级接口)、上报地理位置(普通订阅号不支持)、自定义菜单(普通订阅号不支持)点击)推送三种接口,但高级点的功能如自定义菜单、语音识别、客服接口、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 = 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微信开发系列申请测试账号及回复图文消息相关文章请关注PHP中文网!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

PHP是一种开源的脚本语言,广泛应用于Web开发和服务器端编程,尤其在微信开发中得到了广泛的应用。如今,越来越多的企业和开发者开始使用PHP进行微信开发,因为它成为了一款真正的易学易用的开发语言。在微信开发中,消息的加密和解密是一个非常重要的问题,因为它们涉及到数据的安全性。对于没有加密和解密方式的消息,黑客可以轻松获取到其中的数据,对用户造成威胁

随着微信的普及,越来越多的企业开始将其作为营销工具。而微信群发功能,则是企业进行微信营销的重要手段之一。但是,如果只依靠手动发送,对于营销人员来说是一件极为费时费力的工作。所以,开发一款微信群发工具就显得尤为重要。本文将介绍如何使用PHP开发微信群发工具。一、准备工作开发微信群发工具,我们需要掌握以下几个技术点:PHP基础知识微信公众平台开发开发工具:Sub

在微信公众号开发中,用户标签管理是一个非常重要的功能,可以让开发者更好地了解和管理自己的用户。本篇文章将介绍如何使用PHP实现微信用户标签管理功能。一、获取微信用户openid在使用微信用户标签管理功能之前,我们首先需要获取用户的openid。在微信公众号开发中,通过用户授权的方式获取openid是比较常见的做法。在用户授权完成后,我们可以通过以下代码获取用

随着微信成为了人们生活中越来越重要的一个通讯工具,其敏捷的消息传递功能迅速受到广大企业和个人的青睐。对于企业而言,将微信发展为一个营销平台已经成为趋势,而微信开发的重要性也逐渐凸显。在其中,群发功能更是被广泛使用,那么,作为PHP程序员,如何实现群发消息发送记录呢?下面将为大家简单介绍一下。1.了解微信公众号相关开发知识在了解如何实现群发消息发送记录之前,我

微信是目前全球用户规模最大的社交平台之一,随着移动互联网的普及,越来越多的企业开始意识到微信营销的重要性。在进行微信营销时,客服服务是至关重要的一环。为了更好地管理客服聊天窗口,我们可以借助PHP语言进行微信开发。一、PHP微信开发简介PHP是一种开源的服务器端脚本语言,广泛运用于Web开发领域。结合微信公众平台提供的开发接口,我们可以使用PHP语言进行微信

在微信公众号开发中,投票功能经常被运用。投票功能是让用户快速参与互动的好方式,也是举办活动和调查意见的重要工具。本文将为您介绍如何使用PHP实现微信投票功能。获取微信公众号授权首先,你需要获取微信公众号的授权。在微信公众平台上,你需要配置微信公众号的api地址、官方账号和公众号对应的token。在我们使用PHP语言开发的过程中,我们需要使用微信官方提供的PH

随着互联网和移动智能设备的发展,微信成为了社交和营销领域不可或缺的一部分。在这个越来越数字化的时代,如何使用PHP进行微信开发已经成为了很多开发者的关注点。本文主要介绍如何使用PHP进行微信开发的相关知识点,以及其中的一些技巧和注意事项。一、开发环境准备在进行微信开发之前,首先需要准备好相应的开发环境。具体来说,需要安装PHP的运行环境,以及微信公众平台提

随着移动互联网的普及,微信作为一款社交软件,越来越多的人开始使用,并且微信开放平台也给开发者带来了众多的机会。近年来,随着人工智能技术的发展,语音识别技术逐渐成为了移动端开发的热门技术之一。在微信开发中,如何实现语音识别成为很多开发者关注的问题。本文将介绍如何利用PHP开发微信应用实现语音识别功能。一、语音识别原理在介绍如何实现语音识别之前,我们先了解一下语
