Force.com은 간단한 문자 메시지 답장 외에도 사진과 문자가 포함된 메시지에 답장하고, 음악이나 동영상에 답하고, 사용자가 보낸 음성을 인식하고, 사용자의 지리적 위치 정보를 수집하고, 해당 콘텐츠나 서비스를 제공하는 등의 작업도 수행할 수 있습니다. ., 이 글에서는 이러한 기술을 하나씩 설명하겠습니다. 그 전에 먼저 모든 서비스 계정 인터페이스 기능을 갖춘 테스트 계정을 신청하는 방법을 소개해야 합니다(단, 그래픽 메시지에 응답하는 데는 필요하지 않습니다).
테스트 계정 신청
개인 개발자로서 구독 계정을 신청할 수 있습니다. 구독 계정은 사용자 메시지 수신을 포함한 기본 인터페이스만 열 수 있습니다. 사용자에게 응답 및 이벤트 수락(이벤트 푸시에는 팔로우 또는 언팔로우, 매개변수로 QR 코드 스캔(이러한 QR 코드 생성에는 고급 인터페이스 필요), 지리적 위치 보고(일반 구독 계정에서는 지원되지 않음), 사용자 정의 메뉴(일반 구독에서는 지원되지 않음) 계정) ) 클릭) 세 가지 인터페이스를 푸시하지만 사용자 정의 메뉴, 음성 인식, 고객 서비스 인터페이스, OAuth2.0 웹 페이지 인증, 사용자 지리적 위치 정보 획득 등과 같은 고급 기능을 모두 지원하려면 서비스 계정이 필요하며 그중 인증된 가입이 필요합니다. 계정은 사용자 정의 메뉴를 지원합니다. 개발자가 다른 플랫폼 회사와 마찬가지로 Tencent의 이러한 인터페이스를 쉽게 이해하고 학습할 수 있도록 Tencent는 마침내 작년 말에 테스트 계정 애플리케이션을 오픈했습니다. WeChat 구독 계정이 있는 사람이라면 누구나 신청할 수 있습니다(서비스 계정도 가능해야 하지만 서비스 계정의 백엔드가 어떻게 보이는지 본 적이 없으므로 언급하지 않겠습니다).
신청 방법은 간단하고 직접적입니다. 위챗 백엔드(https://mp.weixin.qq.com)에 들어가시면 최신 버전(7월 6일 기준) 좌측 하단에 버튼이 있습니다. , 2014) 백엔드의 "개발자 센터" 링크를 클릭하면 "인터페이스 테스트 신청 시스템 클릭하여 입력" 링크가 표시되며, Tencent의 아이디어에 따라 신청할 수 있습니다. 여기에 자세히 설명되어 있습니다.
로그인에 성공한 애플리케이션은 다음과 같습니다. 페이지를 스크롤하면 QR 코드가 표시됩니다. WeChat을 통해 이 QR 코드를 스캔하여 이 테스트 계정을 팔로우하세요. 이 테스트 계정은 후속 조치가 성공적으로 완료되면 "WeChat 공개 플랫폼 테스트 계정"이라는 추가 계정이 생성됩니다. " WeChat "구독 계정" 폴더에 있는 "구독 계정" 폴더에 있지만 모든 서비스 계정의 기능을 갖습니다.
다음 작업을 위해 여기서는 먼저 몇 가지 주요 클래스와 해당 처리 프레임워크를 구축하여 후속 기능 지원 추가를 용이하게 합니다.
IncomingMsg: 다양한 주요 필드 정보를 포함하여 사용자가 보낸 메시지 클래스
WeChatNews: 사진과 텍스트로 뉴스에 답할 때의 뉴스 클래스; 클래스 코드는 다음과 같습니다. 다양한 메시지 유형의 대부분의 필드 정보를 포함하여 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 구문 분석 코드를 사용하여 모든 유형의 WeChat 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 ); }
이 메서드를 사용하면 WeChat 메시지 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);
이미지 및 텍스트 전송을 위한 handlerText 메소드 상세 설명
다음으로 이미지 및 텍스트 메시지에 답장하는 방법을 소개하겠습니다. 그래픽 메시지에 답장하기 위해 테스트 계정을 신청할 필요는 없으며 일반 구독 계정만 신청하면 됩니다. 다음은 이 메소드의 전체 코드입니다:
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> music = new Map<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; }</string></string></wechatnews></wechatnews></wechatnews></wechatnews>
代码的思路应该来说比较直接,从第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></title> <description></description><picurl></picurl><url></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></tousername><fromusername></fromusername><createtime>1234567890</createtime><msgtype></msgtype><articlecount></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; }</wechatnews>
了解该方法代码前先要了解回复图文信息的XML格式,关于此点可以参照腾讯公司链接:回复图文消息 ,与前文介绍到的普通文本消息大同小异,可以留意到里面有个ArticleCount字段用来指定回复的消息里能有几条图文新闻,最大是10,超过10则会无法响应;另外Article节点下方每一个item均是一条图文消息。为此,上述代码的第3行先构造一个每条新闻的模板,接着从第4行开始轮询新闻列表里的每一条新闻,并构造相应的XML文。从第8行开始构造整个图文回复的字符串模板,并在第9、10行通过相应参数将模板转换为最终的XML字符串。
再接下来介绍composeMusicReply,该方法的全部代码如下:
private static String composeMusicReply(IncomingMsg msg, Map<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></tousername><fromusername></fromusername><createtime>12345678</createtime><msgtype></msgtype><music><title></title> <description></description><musicurl></musicurl><hqmusicurl></hqmusicurl></music></xml>'; String[] arguments = new String[]{msg.fromUserName, msg.toUserName, strTitle, strDesc, strURL, strHQURL}; String results = String.format(musicTpl, arguments); return results; }</string>
同样了解该方法要首先了解回复音乐信息的XML格式,可以参照腾讯公司链接:回复音乐消息,上面代码与前面方法比较类似,就不再赘述。(这里的Map对象也许有点多余,可以考虑是否可以和回复视频的方法整合到一起,否则不需要额外的Map对象开销,直接将标题、描述、链接等信息传给composeMusicReply方法即可)。
运行效果
完成后直接保存代码便可立即生效,回复图文、多图文、音乐的运行效果分别如下:
更多Force.com WeChat 개발 시리즈는 테스트 계정에 적용되고 그래픽 메시지에 응답합니다.相关文章请关注PHP中文网!