今天下午,微信公众账号后台升级了,最为明显的莫过于服务号收费(300元/次)认证服务,增加了不少接口,应该能满足一部分人的需求,比如回复图片、用户位置定位等等。
本文暂且不讨论服务号升级后,新接口问题。还是针对近期跟网友交流,常见一些问题进行解读。
一、订阅号和服务号的区别
1、信息推送频率
订阅号:每天允许群发一次信息;
服务号:每月允许群发一次信息;
显然,对于资讯类公众账号,至少每天群发一次信息,那么就不能选择服务号。
2、菜单权限
服务号:有菜单权限;
(服务号)(服务号)
上面左边图片是订阅号,右边是服务号,很明显服务号底部多了一个可自己定义的菜单。很多订阅号没有进行设置,用户第一次关注后,不会自动给用户回复任何信息,那么用户第一次进入订阅号,就只能看到空空的桌面,不知道下一步该怎么操作。对于一些常用的功能,菜单直接显示出来,便于用户操作。
3、开发模式权限不同
订阅号:基本权限
服务号:包括自定义菜单、获取用户基本信息、获取用户位置信息等等。
(订阅号)
(服务号,认证前权限)
(服务号,认证后高级权限)
关于订阅号和服务号的差别,大概有上述几种。
二、开发者认证
http://mp.weixin.qq.com进入微信公众账号后台管理系统,服务_>服务中心_>开发模式:
进入开发模式后,首先需要打开右上角开关。
服务号和订阅号开发者认证后,差别在于服务号有AppId和AppSecret,不过这个对一般的开发没有影响,初学者可以忽略。
三、认证开发程序
微信通过url和token认证微信服务器与开发服务器之间的通讯是授权,腾讯提供PHP实例代码,下面的代码是我参照别人代码基础上整理的JSP代码。
<%@ page import="java.net.*" %> <%@ page import="java.math.*" %> <%@ page import="java.io.*" %> <%@ page import="java.text.*"%> <%@page import="java.util.Date"%> <%@page import="org.dom4j.Element"%> <%@page import="org.dom4j.DocumentHelper"%> <%@page import="org.dom4j.Document"%> <%@page import="java.io.IOException"%> <%@page import="java.io.InputStreamReader"%> <%@page import="java.io.BufferedReader"%> <%@page import="java.io.Reader"%> <%@page import="java.security.MessageDigest"%> <%@page import="java.util.Arrays"%> <%@page import="java.util.ArrayList"%> <%@page import="java.util.Collections"%> <%@page import="java.util.List"%> <%@page import="java.util.regex.Matcher"%> <%@page import="java.util.regex.Pattern"%> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <% //WeiXinHandler为内部类不能使用非final类型的对象 final String TOKEN="daniuco"; final HttpServletRequest final_request=request; final HttpServletResponse final_response=response; %> <% class WeiXinHandler{ public void valid(){ String echostr=final_request.getParameter("echostr"); if(null==echostr||echostr.isEmpty()) { responseMsg(); }else{ if(this.checkSignature()) { this.print(echostr); }else{ this.print("error"); } } } //自动回复内容 public void responseMsg() { String postStr=null; try{ postStr=this.readStreamParameter(final_request.getInputStream()); //System.out.print(postStr); }catch(Exception e) { e.printStackTrace(); } //System.out.println(postStr); if (null!=postStr&&!postStr.isEmpty()) { Document document=null; try{ document = DocumentHelper.parseText(postStr); }catch(Exception e){ e.printStackTrace(); } if(null==document) { this.print(""); return; } Element root=document.getRootElement(); String fromUsername = root.elementText("FromUserName"); String toUsername = root.elementText("ToUserName"); String keyword = root.elementTextTrim("Content"); long longTime = new Date().getTime(); String time = longTime/1000 +""; String msgType = root.elementText("MsgType"); String event = root.elementText("Event"); String textTpl = "<xml>"+ "<ToUserName><![CDATA[%1$s]]></ToUserName>"+ "<FromUserName><![CDATA[%2$s]]></FromUserName>"+ "<CreateTime>%3$s</CreateTime>"+ "<MsgType><![CDATA[%4$s]]></MsgType>"+ "<Content><![CDATA[%5$s]]></Content>"+ "<FuncFlag>0</FuncFlag>"+ "</xml>"; String htmlTpl = "<xml>"+ "<ToUserName><![CDATA[%1$s]]></ToUserName>"+ "<FromUserName><![CDATA[%2$s]]></FromUserName>"+ "<CreateTime>%3$s</CreateTime>"+ "<MsgType><![CDATA[%4$s]]></MsgType>" + "[%5$s]" + "</Articles></xml>"; //公用帮助文档 String helpHtml = "\n任何时候,回复\"help\"或者\"帮助\"或者\"?\"三者之一获取最新使用手册。\n\n分类信息([c:新闻],[c:公告],[c:研报]等)\n历史信息([2013-10-05]:某天信息,[d:9]:过去9天之内的信息,[d:-9]:过去9天之前的信息,默认查询范围10天之内)"; if(null!=msgType && !msgType.equals("")) { /** *事件类型 */ if(msgType.equals("event") && event.equals("subscribe")) { //订阅 String subscribeHtml = ""; msgType = "news"; //String helpHtml = "\n任何时候,回复\"help\"或者\"帮助\"二者之一获取最新使用手册。\n分类信息(c:新闻,c:公告,c:研报)\n历史信息([2013-10-05]:某天信息,[d:9]:过去9天之内的信息,[d:-9]:过去9天之前的信息,默认查询范围10天之内)"; String helpPicUrl = "http://www.daniu.co/images/weixin/finance_travel_640_320.jpg"; String helpContentUrl = ""; String helpResults = "<item><Title><![CDATA[欢迎开启财富新旅程]]></Title><Description><![CDATA[" + helpHtml + "]]></Description><PicUrl><![CDATA[" + helpPicUrl +"]]></PicUrl><Url><![CDATA[" + helpContentUrl + "]]></Url></item>"; helpResults = "<ArticleCount>1</ArticleCount><Articles>"+ helpResults; subscribeHtml = helpResults; //System.out.println(subscribeHtml); String resultStr = htmlTpl.format(htmlTpl,fromUsername,toUsername,time,msgType,subscribeHtml); this.print(resultStr); } if(msgType.equals("event") && event.equals("unsubscribe")) { //退订 String subscribeHtml = ""; msgType = "news"; helpHtml = "\n感谢关注daniuco\n\n你订或不订,我都在这里,勤勤恳恳... ..."; String helpPicUrl = "http://www.daniu.co/images/weixin/finance_640_320.png"; String helpContentUrl = ""; String helpResults = "<item><Title><![CDATA[感谢关注金融互联网]]></Title><Description><![CDATA[" + helpHtml + "]]></Description><PicUrl><![CDATA[" + helpPicUrl +"]]></PicUrl><Url><![CDATA[" + helpContentUrl + "]]></Url></item>"; helpResults = "<ArticleCount>1</ArticleCount><Articles>"+ helpResults; subscribeHtml = helpResults; //System.out.println(subscribeHtml); String resultStr = htmlTpl.format(htmlTpl,subscribeHtml); this.print(resultStr); } } if(null!=keyword&&!keyword.equals("")) { /** * *回复文本信息 String msgType = "text"; String contentStr = "系统在开发过程中,敬请期待!"; if(keyword.equals("help") || keyword.equals("帮助")) {//使用手册 contentStr = contentStr + "\n使用手册正在设计中,您可以在以后使用过程中,回复\"help\"或者\"帮助\"二者之一获取最新使用手册。"; } //Autonomy Search contentStr = contentStr + "\n===自动推送测试内容===\n"+ AutonomySearch(keyword); String resultStr = textTpl.format(textTpl,contentStr); /** *回复文本信息结束 */ /** *回复图文信息,最多6条(微信支持10条) */ msgType = "news"; String contentHtml = "";//用户请求关键字 if(keyword.equals("help") || keyword.equals("帮助") || keyword.equals("?") || keyword.equals("?")) {//使用手册 //String helpHtml = "\n任何时候,回复\"help\"或者\"帮助\"二者之一获取最新使用手册。\n分类信息(c:新闻,c:公告,c:研报)\n历史信息([2013-10-05]:某天信息,[d:9]:过去9天之内的信息,[d:-9]:过去9天之前的信息,默认查询范围10天之内)"; String helpPicUrl = "http://www.daniu.co/images/weixin/help_640_320.png"; String helpContentUrl = ""; String helpResults = "<item><Title><![CDATA[由大牛网提供的财富新体验]]></Title><Description><![CDATA[" + helpHtml + "]]></Description><PicUrl><![CDATA[" + helpPicUrl +"]]></PicUrl><Url><![CDATA["+ helpContentUrl +"]]></Url></item>"; helpResults = "<ArticleCount>1</ArticleCount><Articles>"+ helpResults; String resultStr = htmlTpl.format(htmlTpl,helpResults); this.print(resultStr); }else {//智能回复 String reqTpl = "<xml><ToUserName><![CDATA[%1$s]]></ToUserName><FromUserName><![CDATA[%2$s]]></FromUserName><CreateTime>%3$s</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[" + keyword + "]]></Content><MsgId>5937584354468300645</MsgId><OpenId>daniuco</OpenId></xml>"; String reqStr = reqTpl.format(reqTpl,time);//将原始请求信息发送到智能引擎,注意toUsername,fromUsername位置 contentHtml = getRemoteXML(reqStr); // System.out.print(contentHtml); //返回信息到微信服务器 this.print(contentHtml); } //返回信息到微信服务器 //this.print(resultStr); }else{ this.print("Input something..."); } }else { this.print(""); } } //微信接口验证 public boolean checkSignature(){ String signature = final_request.getParameter("signature"); String timestamp = final_request.getParameter("timestamp"); String nonce = final_request.getParameter("nonce"); String token=TOKEN; String[] tmpArr={token,timestamp,nonce}; Arrays.sort(tmpArr); String tmpStr=this.ArrayToString(tmpArr); tmpStr=this.SHA1Encode(tmpStr); if(tmpStr.equalsIgnoreCase(signature)){ return true; }else{ return false; } } //向请求端发送返回数据 public void print(String content){ try{ final_response.getWriter().print(content); final_response.getWriter().flush(); final_response.getWriter().close(); }catch(Exception e){ } } //数组转字符串 public String ArrayToString(String [] arr){ StringBuffer bf = new StringBuffer(); for(int i = 0; i < arr.length; i++){ bf.append(arr[i]); } return bf.toString(); } //sha1加密 public String SHA1Encode(String sourceString) { String resultString = null; try { resultString = new String(sourceString); MessageDigest md = MessageDigest.getInstance("SHA-1"); resultString = byte2hexString(md.digest(resultString.getBytes())); } catch (Exception ex) { } return resultString; } public final String byte2hexString(byte[] bytes) { StringBuffer buf = new StringBuffer(bytes.length * 2); for (int i = 0; i < bytes.length; i++) { if (((int) bytes[i] & 0xff) < 0x10) { buf.append("0"); } buf.append(Long.toString((int) bytes[i] & 0xff,16)); } return buf.toString().toUpperCase(); } //从输入流读取post参数 public String readStreamParameter(ServletInputStream in){ StringBuilder buffer = new StringBuilder(); BufferedReader reader=null; try{ reader = new BufferedReader(new InputStreamReader(in)); String line=null; while((line = reader.readLine())!=null){ buffer.append(line); } }catch(Exception e){ e.printStackTrace(); }finally{ if(null!=reader){ try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return buffer.toString(); } }%> <%! public String getRemoteXML(String reqStr) { HttpURLConnection url_con = null; String responseContent = null; String daniucoUrl = "http://www.daniu.co/openapi"; try { URL url = new URL(daniucoUrl); url_con = (HttpURLConnection) url.openConnection(); url_con.setRequestMethod("POST"); url_con.setDoOutput(true); byte[] b = reqStr.getBytes(); url_con.getOutputStream().write(b,b.length); url_con.getOutputStream().flush(); url_con.getOutputStream().close(); InputStream in = url_con.getInputStream(); BufferedReader rd = new BufferedReader(new InputStreamReader(in,"utf-8")); String tempLine = rd.readLine(); StringBuffer tempStr = new StringBuffer(); String crlf=System.getProperty("line.separator"); while (tempLine != null) { tempStr.append(tempLine); tempStr.append(crlf); tempLine = rd.readLine(); } responseContent = tempStr.toString(); rd.close(); in.close(); } catch (IOException e) { //System.out.print("网络故障",e); } finally { if (url_con != null) { url_con.disconnect(); } } //System.out.println(responseContent); return responseContent; } %> <% WeiXinHandler t=new WeiXinHandler(); t.valid(); %>
在上述代码中找到
TOKEN="daniuco";
,将“daniuco”更改为你自己的token,保存为jsp文件,如weixinprocess.jsp(注意使用utf-8编码)。
有些初次接触微信开发的朋友,不明白weixinprocess.jsp文件是如何工作的,实际上该文件是用户提交信息到微信公众账号后,腾讯服务器与开发者服务器之间通讯的唯一文件,所以后期的业务处理都在该文件完成,其工作流程图如下:
上行数据流: 用户--》微信公众账号--》开发者服务器(业务处理、weixinprocess.jsp)
下行数据: 开发者服务器(业务处理weixinprocess.jsp)--》微信服务器--》公众账号--》用户
weixinprocess.jsp文件核心的部分是对用户的信息进行处理,即以下部分:
//自动回复信息 public void responseMsg() { }
下面对核心业务进行分解。
String postStr=null; try{ postStr=this.readStreamParameter(final_request.getInputStream()); //System.out.print(postStr); }catch(Exception e) { e.printStackTrace(); } //System.out.println(postStr);
上述代码,用于接收从微信服务器传递过来的用户信息,postStr数据格式如下:
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[this is a test]]></Content> <MsgId>1234567890123456</MsgId> </xml>
当然,用户信息分为文本信息、音乐信息、位置信息等等,参加微信开发手册http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF,这里我们只讲文本信息(代码<MsgType><![CDATA[text]]></MsgType>)和事件信息。
当我们拿到用户信息(<MsgType><![CDATA[text]]></MsgType>)后,我们就要对信息进行处理,根据开发者提供服务的不同,信息处理方法多种多样。本文主要讲对资讯类公众账户如何处理用户信息,并将处理结果返回给用户。在讲信息处理前,我们要先介绍一下资讯类特点,一般现在的资讯类公众账号(如:央视新闻、钱江晚报、每日经济新闻等)都是订阅号,每天定时给用户推送当日热点新闻。当用户需要对过去某一天的新闻进行阅读,或者是只记得某一个主题,不确定时间的信息进行阅读时,用户希望给这些公众账号发送一些简单指令(如:2013-10-01、d:-29等),微信公众账号把2013-10-01当天的新闻返回给用户。用户的需求很简单,但是遗憾的是现在大部分资讯类公众账号都没有实现该功能,微信的互动功能没有得到利用。
本人下面要针对上文用户互动需求,利用第三方开放接口,实现对用户信息进行智能语义识别,并自动返回结果给用户。
getRemoteXML(reqStr)
出于成本等方面原因,很多开发者并不能实现智能语音识别用户信息,我们恰恰能对中文语义处理,那么我们就把复杂的语义处理、搜索引擎等技术打包,作为第三方开放接口提供给开发者使用,开发者只需要获取他们能识别的用户信息,把不能识别的信息发送到第三方接口,将第三方接口的返回信息直接返回给微信服务器。
public String getRemoteXML(String reqStr) { HttpURLConnection url_con = null; String responseContent = null; String daniucoUrl = "http://www.daniu.co/openapi"; try { URL url = new URL(daniucoUrl); url_con = (HttpURLConnection) url.openConnection(); url_con.setRequestMethod("POST"); url_con.setDoOutput(true); byte[] b = reqStr.getBytes(); url_con.getOutputStream().write(b,e); } finally { if (url_con != null) { url_con.disconnect(); } } //System.out.println(responseContent); return responseContent; }
上文“ http://www.daniu.co/openapi”就是我们说的第三方接口,开发者把用户信息按照以下格式发送到接口服务器:
<xml> <ToUserName><![CDATA[gh_300a01a0d7f9]]></ToUserName> <FromUserName><![CDATA[o7IXQjop1XEJ71IVWi-3tUqzJDxw]]></FromUserName> <CreateTime>1382451587</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[2013-10-01]]></Content> <MsgId>5937584354468300645</MsgId> <OpenId>daniuco</OpenId> </xml>
可以看到,数据格式类似微信服务器发送的格式,只是多了“<OpenId>daniuco</OpenId> ”,这是因为开发接口是公用服务器,为了识别是哪个开发者提交的请求。OpenId需要跟第三方接口申请。
第三方接口接收到请求后,对请求信息进行处理“ <Content><![CDATA[2013-10-01]]></Content>”。以上述代码为例,第三方接口通过正则表达式,认为“2013-10-01”是一个日期格式信息,那么服务器自动搜索OpenId所属的2013-10-01的相关资讯,并以图文信息的方式返回给开发者,开发者可以不做任何处理,直接将信息返回给微信服务器。
这个业务处理流程:
上行:用户信息--》微信服务器--》开发者服务器--》第三方接口
下行:第三方接口--》开发者服务器--》微信服务器--》用户信息
也就是说,通过第三方接口,开发者节省了大量开发工作,而用户却得到极大的互动体验。
三、第三方接口数据索引
1、OpenId申请
开发者如果要使用第三方接口,需要申请得到相应的OpenId,目前申请完全免费(加QQ群314207039微信创业圈找群主申请)。
2、数据索引
要让第三方接口能处理开发者的数据,前提是需要开发者将每次群发的信息,以正确的格式以POST方式提交到第三方接口(“ http://www.daniu.co/inputapi?openid=”) ,格式如下:
<xml> <DOCUMENT> <OPENID>daniuco</OPENID> <DREDATE>1382923664</DREDATE> <DATE>2013-10-28 01:01</DATE> <DRETITLE>金科股份定增新方案缩水11.8亿元 今年拿地已耗资70亿</DRETITLE> <URL>http://business.sohu.com/20131028/n389016522.shtml</URL> <DREDBNAME>NEWS</DREDBNAME> <CONTENT>每日经济新闻记者 杜冉乐 发自成都 在房地产再融资未取得实质性开闸之前,部分上市房企开始调整相关预案,以求得“闯关”成功。 10月26日,《每日经济新闻》记者注意到,在金科股份(000656,SZ)最新公告中,公司修订了之前发布的定增预案,拟发行总股份由原来 相关公司股票走势金科股份迪马股份东北证券中房地产 的4亿股,调减为2.9亿股,募集金额由原来的43.2亿元缩减为31.4亿元。值得注意的是,金科股份取消了“西安金科天籁城”募投项目,也砍掉了3.3亿元的“补充流动资金”事项。 对此,金科股份副总裁、首席战略执行官李战洪在接受记者采访时表示,“我在外地开会,不太清楚这个事情。” 即便如此,金科股份仍未放缓土地扩张步伐。截至目前,金科股份拿地耗资70亿元,但拿地成本较低,主要集中在三、四线城市。长城证券研报认为,金科股份深耕大重庆区域,战略积极,销售增长强劲,多元化拿地模式亦将强化成本优势,短期流动性安全。 金科股份调整定增预案/ 截至目前,国内已有33家上市房企公布再融资预案,涉及融资金额高达770亿元。近日,来自重庆的迪马股份成为首家获得证监会公开受理的上市房企。 不过,在这之前,迪马股份曾经历过一次预案修订,其中涉及公司与控股股东东银控股集团之间的关联交易及后者对上市公司的巨额占款等问题。 如今,金科股份似有步其后尘之势。在10月26日的公告中,金科股份已修订了之前43.2亿元的定增方案,改为定向募资31.4亿元,定增总股份由4亿股调整为约2.9亿股。其中,金科股份原本一共定增募投三个项目,现在也改成了两个项目,西安项目已被取消。 昨日,记者致电李战洪,其表示在外地开会,不太清楚此事。重庆一位熟悉金科股份的券商人士认为,最大可能性应是 “资金成本”问题,金科股份的定增对象都会有一个回报率的要求,原本谈好的买家现在可能放弃了定向受让股份。 据了解,西安项目是金科股份通过收购陕西一房企的100%股权,从而“曲线”获得93亩已获得土地证的相关地块,收购代价为2000万元。不过,对于西安项目,金科股份仍有近6亿元的项目债务需要偿付。 在定增方案中,金科股份曾宣称,西安项目将要配建超过1.2万平方米的廉租房,这也为公司插上了符合国家政策导向的有利标签。据项目测算报告显示,该项目总销售额26.2亿元,总开发成本16.9亿元,销售毛利率35.4%,净利润率16.3%。 不过,金科股份还透露,目前西安项目详细的定位方案及规划设计尚在编制及审批过程中。 公司深耕三、四线城市/ 与其他成长型房企一样,金科股份虽然负债率较高,但截至8月15日公司账面资金余额仍高达94.7亿元,同时,金科股份在土地储备上也不遗余力。 据公开披露的信息,《每日经济新闻》记者统计得出,截至目前,金科股份花在拿地上的资金已达70.5亿元,其中权益性拿地约65亿元,主要集中在大重庆以及江苏无锡、四川内江、贵州遵义等三、四线城市。按照计划,金科股份今年拿地的金额将不少于去年的92.6亿元。 东北证券地产分析师高建认为,金科股份深耕重庆,异地拓展稳扎稳打,市场对公司区域发展战略的看法有失偏颇,获取优质低价土地的能力以及标准化和精细的进度管理能力是快速周转的保证。 一线品牌房企自去年下半年以来开始重回“一、二线”城市,主流看法是三、四线城市消费能力有限,供给偏多,可能存在一定的开发风险。不过,包括金科股份在内的部分房企却依靠低成本策略,深耕三、四线城市,取得了不错的业绩。 数据显示,今年上半年,金科股份实现销售金额91亿元,同比增长58.8%,其中房地产业务实现签约销售金额84.7亿元,同比增长59.2%;实现销售面积113万平方米,同比增长41%。 值得一提的是,考虑到市场和公司实际情况,金科股份下调了年度销售目标,由年初制定的235亿元调至220亿元(含产业板块)。为了加速销售,金科股份在下半年推盘项目中将刚需产品比例从原有的70%提高到了80%。 在瑞银证券分析师李宗彬看来,金科股份在2012年新开工及今年计划开工面积中,三、四线城市的占比或超过60%,公司在这些城市的销售可能受制于当地较大的供给,难以快速增长,因此瑞银证券将金科股份2013年的销售额下调至206亿元。 不过,李战洪前不久曾公开表示,“随着城镇化建设进程的推进,金科股份察觉到,二、三线城市必然蕴含着更大的市场。” 作者:杜冉乐 http://business.sohu.com/20131028/n389016522.shtml business.sohu.com false 每日经济新闻 http://www.nbd.com.cn/articles/2013-10-28/782711.html report 3109 每日经济新闻记者杜冉乐发自成都在房地产再融资未取得实质性开闸之前,部分上市房企开始调整相关预案,以求得“闯关”成功。10月26日,《每日经济新闻》记者注意到,在</CONTENT> </DOCUMENT> <DOCUMENT> </xml>
<DOCUMENT></DOCUMENT>是一条完整记录,有多条记录循环加入即可。
<xml> <DOCUMENT> <OPENID>daniuco</OPENID> <DREDATE>1382923664</DREDATE> <DATE>2013-10-28 01:01</DATE> <DRETITLE></DRETITLE> <URL></URL> <DREDBNAME>NEWS</DREDBNAME> <CONTENT></CONTENT> </DOCUMENT> <DOCUMENT> <OPENID>daniuco</OPENID> <DREDATE>1382923664</DREDATE> <DATE>2013-10-28 01:01</DATE> <DRETITLE></DRETITLE> <URL></URL> <DREDBNAME>NEWS</DREDBNAME> <CONTENT></CONTENT> </DOCUMENT> <DOCUMENT> <OPENID>daniuco</OPENID> <DREDATE>1382923664</DREDATE> <DATE>2013-10-28 01:01</DATE> <DRETITLE></DRETITLE> <URL></URL> <DREDBNAME>NEWS</DREDBNAME> <CONTENT></CONTENT> </DOCUMENT> </xml>
到此,公众账号开发模式完成,开发者的工作量除了将weixinprocess.jsp必要修改放到服务器,在公众账号管理系统认证开发之外,就是将每次下发的数据索引到第三方接口供微信用户互动。
为了交流方便,公布一下QQ群314207039。
原文链接:/regex/362413.html