说明:
本次的教程主要是对微信公众平台开发者模式的讲解,网络上很多类似文章,但很多都让初学微信开发的人一头雾水,所以总结自己的微信开发经验,将微信开发的整个过程系统的列出,并对主要代码进行讲解分析,让初学者尽快上手。
在阅读本文之前,应对微信公众平台的官方开发文档有所了解,知道接收和发送的都是xml格式的数据。另外,在做内容回复时用到了捷微JEEWX,这是一个自然语言解析的开放平台,可以帮我们解决整个微信开发过程中最困难的问题,此处不多讲,下面会有其详细的调用方式。
下面就讲解其核心部分——解析接收到的xml数据,并以文本类消息为例,通过图灵机器人api接口实现智能回复。
2.1 首先看一下整体流程处理代码,包括:xml数据处理、调用图灵api、封装返回的xml数据。
本次的教程主要是对微信公众平台开发者模式的讲解,网络上很多类似文章,但很多都让初学微信开发的人一头雾水,所以总结自己的微信开发经验,将微信开发的整个过程系统的列出,并对主要代码进行讲解分析,让初学者尽快上手。
在阅读本文之前,应对微信公众平台的官方开发文档有所了解,知道接收和发送的都是xml格式的数据。另外,在做内容回复时用到了捷微JEEWX,这是一个自然语言解析的开放平台,可以帮我们解决整个微信开发过程中最困难的问题,此处不多讲,下面会有其详细的调用方式。
1.1 在登录微信官方平台之后,开启开发者模式,此时需要我们填写url和token,所谓url就是我们自己服务器的接口,用WechatServlet.java来实现,相关解释已经在注释中说明,代码如下:
- packagedemo.servlet;
- importjava.io.BufferedReader;
- importjava.io.IOException;
- importjava.io.InputStream;
- importjava.io.InputStreamReader;
- importjava.io.OutputStream;
- importjavax.servlet.ServletException;
- importjavax.servlet.http.HttpServlet;
- importjavax.servlet.http.HttpServletRequest;
- importjavax.servlet.http.HttpServletResponse;
- importdemo.process.WechatProcess;
- /**
- *微信服务端收发消息接口
- *
- *@authorpamchen-1
- *
- */
- publicclassWechatServletextendsHttpServlet{
- /**
- *ThedoGetmethodoftheservlet.<br>
- *
- *Thismethodiscalledwhenaformhasitstagvaluemethodequalstoget.
- *
- *@paramrequest
- *therequestsendbytheclienttotheserver
- *@paramresponse
- *theresponsesendbytheservertotheclient
- *@throwsServletException
- *ifanerroroccurred
- *@throwsIOException
- *ifanerroroccurred
- */
- publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
- throwsServletException,IOException{
- request.setCharacterEncoding("UTF-8");
- response.setCharacterEncoding("UTF-8");
- /**读取接收到的xml消息*/
- StringBuffersb=newStringBuffer();
- InputStreamis=request.getInputStream();
- InputStreamReaderisr=newInputStreamReader(is,"UTF-8");
- BufferedReaderbr=newBufferedReader(isr);
- Strings="";
- while((s=br.readLine())!=null){
- sb.append(s);
- }
- Stringxml=sb.toString();//次即为接收到微信端发送过来的xml数据
- Stringresult="";
- /**判断是否是微信接入激活验证,只有首次接入验证时才会收到echostr参数,此时需要把它直接返回*/
- Stringechostr=request.getParameter("echostr");
- if(echostr!=null&&echostr.length()>1){
- result=echostr;
- }else{
- //正常的微信处理流程
- result=newWechatProcess().processWechatMag(xml);
- }
- try{
- OutputStreamos=response.getOutputStream();
- os.write(result.getBytes("UTF-8"));
- os.flush();
- os.close();
- }catch(Exceptione){
- e.printStackTrace();
- }
- }
- /**
- *ThedoPostmethodoftheservlet.<br>
- *
- *Thismethodiscalledwhenaformhasitstagvaluemethodequalsto
- *post.
- *
- *@paramrequest
- *therequestsendbytheclienttotheserver
- *@paramresponse
- *theresponsesendbytheservertotheclient
- *@throwsServletException
- *ifanerroroccurred
- *@throwsIOException
- *ifanerroroccurred
- */
- publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)
- throwsServletException,IOException{
- doGet(request,response);
- }
- }
1.2 相应的web.xml配置信息如下,在生成WechatServlet.java的同时,可自动生成web.xml中的配置。前面所提到的url处可以填写例如:http;//服务器地址/项目名/wechat.do
- <?xmlversion="1.0"encoding="UTF-8"?>
- <web-appversion="2.5"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
- <servlet>
- <description>ThisisthedescriptionofmyJ2EEcomponent</description>
- <display-name>ThisisthedisplaynameofmyJ2EEcomponent</display-name>
- <servlet-name>WechatServlet</servlet-name>
- <servlet-class>demo.servlet.WechatServlet</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>WechatServlet</servlet-name>
- <url-pattern>/wechat.do</url-pattern>
- </servlet-mapping>
- <welcome-file-list>
- <welcome-file>index.jsp</welcome-file>
- </welcome-file-list>
- </web-app>
1.3 通过以上代码,我们已经实现了微信公众平台开发的框架,即开通开发者模式并成功接入、接收消息和发送消息这三个步骤。
下面就讲解其核心部分——解析接收到的xml数据,并以文本类消息为例,通过图灵机器人api接口实现智能回复。
2.1 首先看一下整体流程处理代码,包括:xml数据处理、调用图灵api、封装返回的xml数据。
- packagedemo.process;
- importjava.util.Date;
- importdemo.entity.ReceiveXmlEntity;
- /**
- *微信xml消息处理流程逻辑类
- *@authorpamchen-1
- *
- */
- publicclassWechatProcess{
- /**
- *解析处理xml、获取智能回复结果(通过图灵机器人api接口)
- *@paramxml接收到的微信数据
- *@return最终的解析结果(xml格式数据)
- */
- publicStringprocessWechatMag(Stringxml){
- /**解析xml数据*/
- ReceiveXmlEntityxmlEntity=newReceiveXmlProcess().getMsgEntity(xml);
- /**以文本消息为例,调用图灵机器人api接口,获取回复内容*/
- Stringresult="";
- if("text".endsWith(xmlEntity.getMsgType())){
- result=newTulingApiProcess().getTulingResult(xmlEntity.getContent());
- }
- /**此时,如果用户输入的是“你好”,在经过上面的过程之后,result为“你也好”类似的内容
- *因为最终回复给微信的也是xml格式的数据,所有需要将其封装为文本类型返回消息
- **/
- result=newFormatXmlProcess().formatXmlAnswer(xmlEntity.getFromUserName(),xmlEntity.getToUserName(),result);
- returnresult;
- }
- }
2.2 解析接收到的xml数据,此处有两个类,ReceiveXmlEntity.java和ReceiveXmlProcess.java,通过反射的机制动态调用实体类中的set方法,可以避免很多重复的判断,提高代码效率,代码如下:
- packagedemo.entity;
- /**
- *接收到的微信xml实体类
- *@authorpamchen-1
- *
- */
- publicclassReceiveXmlEntity{
- privateStringToUserName="";
- privateStringFromUserName="";
- privateStringCreateTime="";
- privateStringMsgType="";
- privateStringMsgId="";
- privateStringEvent="";
- privateStringEventKey="";
- privateStringTicket="";
- privateStringLatitude="";
- privateStringLongitude="";
- privateStringPrecision="";
- privateStringPicUrl="";
- privateStringMediaId="";
- privateStringTitle="";
- privateStringDescription="";
- privateStringUrl="";
- privateStringLocation_X="";
- privateStringLocation_Y="";
- privateStringScale="";
- privateStringLabel="";
- privateStringContent="";
- privateStringFormat="";
- privateStringRecognition="";
- publicStringgetRecognition(){
- returnRecognition;
- }
- publicvoidsetRecognition(Stringrecognition){
- Recognition=recognition;
- }
- publicStringgetFormat(){
- returnFormat;
- }
- publicvoidsetFormat(Stringformat){
- Format=format;
- }
- publicStringgetContent(){
- returnContent;
- }
- publicvoidsetContent(Stringcontent){
- Content=content;
- }
- publicStringgetLocation_X(){
- returnLocation_X;
- }
- publicvoidsetLocation_X(StringlocationX){
- Location_X=locationX;
- }
- publicStringgetLocation_Y(){
- returnLocation_Y;
- }
- publicvoidsetLocation_Y(StringlocationY){
- Location_Y=locationY;
- }
- publicStringgetScale(){
- returnScale;
- }
- publicvoidsetScale(Stringscale){
- Scale=scale;
- }
- publicStringgetLabel(){
- returnLabel;
- }
- publicvoidsetLabel(Stringlabel){
- Label=label;
- }
- publicStringgetTitle(){
- returnTitle;
- }
- publicvoidsetTitle(Stringtitle){
- Title=title;
- }
- publicStringgetDescription(){
- returnDescription;
- }
- publicvoidsetDescription(Stringdescription){
- Description=description;
- }
- publicStringgetUrl(){
- returnUrl;
- }
- publicvoidsetUrl(Stringurl){
- Url=url;
- }
- publicStringgetPicUrl(){
- returnPicUrl;
- }
- publicvoidsetPicUrl(StringpicUrl){
- PicUrl=picUrl;
- }
- publicStringgetMediaId(){
- returnMediaId;
- }
- publicvoidsetMediaId(StringmediaId){
- MediaId=mediaId;
- }
- publicStringgetEventKey(){
- returnEventKey;
- }
- publicvoidsetEventKey(StringeventKey){
- EventKey=eventKey;
- }
- publicStringgetTicket(){
- returnTicket;
- }
- publicvoidsetTicket(Stringticket){
- Ticket=ticket;
- }
- publicStringgetLatitude(){
- returnLatitude;
- }
- publicvoidsetLatitude(Stringlatitude){
- Latitude=latitude;
- }
- publicStringgetLongitude(){
- returnLongitude;
- }
- publicvoidsetLongitude(Stringlongitude){
- Longitude=longitude;
- }
- publicStringgetPrecision(){
- returnPrecision;
- }
- publicvoidsetPrecision(Stringprecision){
- Precision=precision;
- }
- publicStringgetEvent(){
- returnEvent;
- }
- publicvoidsetEvent(Stringevent){
- Event=event;
- }
- publicStringgetMsgId(){
- returnMsgId;
- }
- publicvoidsetMsgId(StringmsgId){
- MsgId=msgId;
- }
- publicStringgetToUserName(){
- returnToUserName;
- }
- publicvoidsetToUserName(StringtoUserName){
- ToUserName=toUserName;
- }
- publicStringgetFromUserName(){
- returnFromUserName;
- }
- publicvoidsetFromUserName(StringfromUserName){
- FromUserName=fromUserName;
- }
- publicStringgetCreateTime(){
- returnCreateTime;
- }
- publicvoidsetCreateTime(StringcreateTime){
- CreateTime=createTime;
- }
- publicStringgetMsgType(){
- returnMsgType;
- }
- publicvoidsetMsgType(StringmsgType){
- MsgType=msgType;
- }
- }
- packagedemo.process;
- importjava.lang.reflect.Field;
- importjava.lang.reflect.Method;
- importjava.util.Iterator;
- importorg.dom4j.Document;
- importorg.dom4j.DocumentHelper;
- importorg.dom4j.Element;
- importdemo.entity.ReceiveXmlEntity;
- /**
- *解析接收到的微信xml,返回消息对象
- *@authorpamchen-1
- *
- */
- publicclassReceiveXmlProcess{
- /**
- *解析微信xml消息
- *@paramstrXml
- *@return
- */
- publicReceiveXmlEntitygetMsgEntity(StringstrXml){
- ReceiveXmlEntitymsg=null;
- try{
- if(strXml.length()<=0||strXml==null)
- returnnull;
- //将字符串转化为XML文档对象
- Documentdocument=DocumentHelper.parseText(strXml);
- //获得文档的根节点
- Elementroot=document.getRootElement();
- //遍历根节点下所有子节点
- Iterator<?>iter=root.elementIterator();
- //遍历所有结点
- msg=newReceiveXmlEntity();
- //利用反射机制,调用set方法
- //获取该实体的元类型
- Class<?>c=Class.forName("demo.entity.ReceiveXmlEntity");
- msg=(ReceiveXmlEntity)c.newInstance();//创建这个实体的对象
- while(iter.hasNext()){
- Elementele=(Element)iter.next();
- //获取set方法中的参数字段(实体类的属性)
- Fieldfield=c.getDeclaredField(ele.getName());
- //获取set方法,field.getType())获取它的参数数据类型
- Methodmethod=c.getDeclaredMethod("set"+ele.getName(),field.getType());
- //调用set方法
- method.invoke(msg,ele.getText());
- }
- }catch(Exceptione){
- //TODO:handleexception
- System.out.println("xml格式异常:"+strXml);
- e.printStackTrace();
- }
- returnmsg;
- }
- }
2.3调用捷微JEEWXapi接口,获取智能回复内容:
- packagedemo.process;
- importjava.io.IOException;
- importjava.io.UnsupportedEncodingException;
- importjava.net.URLEncoder;
- importorg.apache.http.HttpResponse;
- importorg.apache.http.client.ClientProtocolException;
- importorg.apache.http.client.methods.HttpGet;
- importorg.apache.http.impl.client.HttpClients;
- importorg.apache.http.util.EntityUtils;
- importorg.json.JSONException;
- importorg.json.JSONObject;
- /**
- *调用图灵机器人api接口,获取智能回复内容
- *@authorpamchen-1
- *
- */
- publicclassTulingApiProcess{
- /**
- *调用图灵机器人api接口,获取智能回复内容,解析获取自己所需结果
- *@paramcontent
- *@return
- */
- publicStringgetTulingResult(Stringcontent){
- /**此处为图灵api接口,参数key需要自己去注册申请,先以11111111代替*/
- StringapiUrl="http://www.tuling123.com/openapi/api?key=11111111&info=";
- Stringparam="";
- try{
- param=apiUrl+URLEncoder.encode(content,"utf-8");
- }catch(UnsupportedEncodingExceptione1){
- //TODOAuto-generatedcatchblock
- e1.printStackTrace();
- }//将参数转为url编码
- /**发送httpget请求*/
- HttpGetrequest=newHttpGet(param);
- Stringresult="";
- try{
- HttpResponseresponse=HttpClients.createDefault().execute(request);
- if(response.getStatusLine().getStatusCode()==200){
- result=EntityUtils.toString(response.getEntity());
- }
- }catch(ClientProtocolExceptione){
- e.printStackTrace();
- }catch(IOExceptione){
- e.printStackTrace();
- }
- /**请求失败处理*/
- if(null==result){
- return"对不起,你说的话真是太高深了……";
- }
- try{
- JSONObjectjson=newJSONObject(result);
- //以code=100000为例,参考图灵机器人api文档
- if(100000==json.getInt("code")){
- result=json.getString("text");
- }
- }catch(JSONExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }
- returnresult;
- }
- }
2.4 将结果封装为微信规定的xml格式,并返回给1.1中创建的servlet接口。
- packagedemo.process;
- importjava.util.Date;
- /**
- *封装最终的xml格式结果
- *@authorpamchen-1
- *
- */
- publicclassFormatXmlProcess{
- /**
- *封装文字类的返回消息
- *@paramto
- *@paramfrom
- *@paramcontent
- *@return
- */
- publicStringformatXmlAnswer(Stringto,Stringfrom,Stringcontent){
- StringBuffersb=newStringBuffer();
- Datedate=newDate();
- sb.append("<xml><ToUserName><![CDATA[");
- sb.append(to);
- sb.append("]]></ToUserName><FromUserName><![CDATA[");
- sb.append(from);
- sb.append("]]></FromUserName><CreateTime>");
- sb.append(date.getTime());
- sb.append("</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[");
- sb.append(content);
- sb.append("]]></Content><FuncFlag>0</FuncFlag></xml>");
- returnsb.toString();
- }
- }
总结,以上便是微信公众平台开发的全部流程,整体来看并不复杂,要非常感谢捷微JEEWX,帮我们解决了智能回复这一高难度问题。其他类型的消息处理与示例中类似,有兴趣的开发者可以联系我进行交流学习,希望本文对大家有所帮助。