热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

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

申请测试账号

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

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

基础框架搭建

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

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 newsList = new List();
            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 newsList = new List();
            newsList.add(news1);
            newsList.add(news2);
            newsList.add(news3);
            strResult = composeNewsReply(msg, newsList);
        }
        else if(keyword.equals('音乐')){
            Map music = new Map();
            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 newsList){
        String strNews = '';
        String newsTpl = '';
        for(WeChatNews news : newsList){
            String[] arguments = new String[]{news.title, news.description, news.picUrl, news.url};
            strNews += String.format(newsTpl, arguments);
        }
        String strTmp = '1234567890' + strNews + '';
        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 music){
        String strTitle = music.get('title');
        String strDesc = music.get('description');
        String strURL = music.get('musicUrl');
        String strHQURL = music.get('musicHQUrl');
        String musicTpl = '12345678';
        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微信开发系列申请测试账号及回复图文消息相关文章请关注!

推荐阅读
  • C#爬虫Fiddler插件开发自动生成代码
    哈喽^_^一般我们在编写网页爬虫的时候经常会使用到Fiddler这个工具来分析http包,而且通常并不是分析一个包就够了的,所以为了把更多的时间放在分析http包上,自动化生成 ... [详细]
  • 本文介绍如何使用Java实现AC自动机(Aho-Corasick算法),以实现高效的多模式字符串匹配。文章涵盖了Trie树和KMP算法的基础知识,并提供了一个详细的代码示例,包括构建Trie树、设置失败指针以及执行搜索的过程。 ... [详细]
  • 使用EF Core在.Net Core控制台应用中操作SQLite数据库
    本文介绍如何利用Visual Studio 2019和Windows 10环境,通过Entity Framework Core(EF Core)实现对SQLite数据库的读写操作。项目源代码可从百度网盘下载。 ... [详细]
  • 本文介绍了一种算法,用于在一个给定的二叉树中找到一个节点,该节点的子树包含最大数量的值小于该节点的节点。如果存在多个符合条件的节点,可以选择任意一个。 ... [详细]
  • MVC框架下使用DataGrid实现时间筛选与枚举填充
    本文介绍如何在ASP.NET MVC项目中利用DataGrid组件增强搜索功能,具体包括使用jQuery UI的DatePicker插件添加时间筛选条件,并通过枚举数据填充下拉列表。 ... [详细]
  • 帝国cms各数据表有什么用
    CMS教程|帝国CMS帝国cmsCMS教程-帝国CMS精易编程助手源码,ubuntu桥接设置,500错误是tomcat吗,爬虫c原理,php会话包括什么,营销seo关键词优化一般多 ... [详细]
  • 本文详细介绍了如何将After Effects中的动画相机数据导入到Vizrt系统中,提供了一种有效的解决方案,适用于需要在广播级图形制作中使用AE动画的专业人士。 ... [详细]
  • 使用 ModelAttribute 实现页面数据自动填充
    本文介绍了如何利用 Spring MVC 中的 ModelAttribute 注解,在页面跳转后自动填充表单数据。主要探讨了两种实现方法及其背后的原理。 ... [详细]
  • 本文详细介绍了 Go 语言的关键特性和编程理念,包括其强大的并发处理能力、简洁的语法设计以及高效的开发效率。 ... [详细]
  • 提升接口测试效率的关键:用例与工具的综合应用
    本文将探讨如何通过有效的接口测试用例设计和工具选择,显著提高接口测试的效率和质量。 ... [详细]
  • 本文详细介绍了MySQL表分区的概念、类型及其在实际应用中的实施方法,特别是针对Zabbix数据库的优化策略。 ... [详细]
  • 在现代移动应用开发中,尤其是iOS应用,处理来自服务器的JSON数据是一项基本技能。无论是使用Swift还是PHP,有效地解析和利用JSON数据对于提升用户体验至关重要。本文将探讨如何在Swift中优雅地处理JSON,以及PHP中处理JSON的一些技巧。 ... [详细]
  • 本文详细介绍如何在Spring Boot项目中集成和使用JPA,涵盖JPA的基本概念、Spring Data JPA的功能以及具体的操作步骤,帮助开发者快速掌握这一强大的持久化技术。 ... [详细]
  • 本文介绍了如何利用snownlp库对微博内容进行情感分析,包括安装、基本使用以及如何自定义训练模型以提高分析准确性。 ... [详细]
  • 微信小程序支付官方参数小程序中代码后端发起支付代码支付回调官方参数文档地址:https:developers.weixin.qq.comminiprogramdeva ... [详细]
author-avatar
情系50后_989
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有