Salesforce Force.com Site 集成微信公众平台 (四) 图文消息处理

这一篇我们以图文消息为例,来给大家讲解在 Salesforce 中是如何发送和接收的。

首先我们在 Salesforce 中创建一个类用来保存用户发送过来的消息。这个类我们叫它 ReceiveMsg ,代码如下

public class ReceiveMsg  
{
    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 ReceiveMsg(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;
    }
}

这个类中有12个属性,包含了绝大部分消息类型的字段信息。

接下来我们创建一个回复图文消息的类,这个类我们叫它 ReplyMsg ,代码如下

public class ReplyMsg  
{
    public String title;
    public String description;
    public String picUrl;
    public String url;

    public ReplyMsg(String t, String d, String p, String u)
    {
        this.title = t;
        this.description = d;
        this.picUrl = p;
        this.url = u;
    }
}

这个类中定义了一条详细的新闻信息。

接下来我们重新构造 doPost 方法,并使它能够解析任何类型的 XML 内容。修改后代码如下

@HttpPost
global static void doPost()  
{
    //Receive message from user;
    RestRequest req = RestContext.request;
    RestResponse res = RestContext.response;
    string strMsg = req.requestBody.toString();
    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();
    }
    ReceiveMsg receiveMsg = new ReceiveMsg(toUserName, fromUserName, msgType, picURL, mediaID, locationX, locationY, URL, content, event, eventKey, recognition );
}

该方法里,我们对所有微信消息类型的 XML 进行了解析,并通过解析回来的值初始化了 ReceiveMsg 对象,接下来,我们将通过传递这个对象调用不同的方法完成各种任务。最后我们在 doPost 方法的结尾加上以下代码:

String rtnMsg = '';  
//回复消息
if(msgType.equals('text')){  
   rtnMsg = handleText(receiveMsg);
}
RestContext.response.addHeader('Content-Type', 'text/plain');  
RestContext.response.responseBody = Blob.valueOf(rtnMsg);  

这段代码里首先定义了一个返回 XML 的 String 字符串,接着判断如果用户发来的消息类型是文本类型,则调用一个 handleText 的方法来处理回复信息,这里传递给 handleText 方法的对象正是我们前面定义的 ReceiveMsg 对象,在这个方法中我们可以定制我们需要的功能,随后通过 RestContext 即可将 XML 消息返回给微信,最后返回给发送消息的用户。

接下来我们对 handleText 方法进行详解。代码如下

private static String handleText(ReceiveMsg msg)  
{
    String keyword = msg.content;
    String strReply;
    String strResult;
    if(keyword.equals('文本'))
    {
        strReply = '这是个文本消息';
        strResult = composeTextReply(msg, strReply);
    }
    else if(keyword.equals('图文'))
    {
        ReplyMsg news = new ReplyMsg('Meginfo Blog', 'Salesforce Force.com Site 集成微信公众平台 (四) 图文消息处理', 'https://secure.sfdcstatic.com/common/assets/img/logo-tag-company.png', 'http://blog.meginfo.com/');
        List<ReplyMsg> newsList = new List<ReplyMsg>();
        newsList.add(news);
        strResult = composeNewsReply(msg, newsList);
    }
    return strResult;
}

首先我们来看第一个 if 语句,如果用户发送过来的信息是"文本",将满足这个条件,并把 strReply 的值传到 composeTextReply 方法中完成XML构建。如果用户发过来的信息是"图文",那么将进入else if语句,并返回给用户单图文信息,这里先构造了一个 ReplyMsg 数组,当然数组里只有一个 ReplyMsg 对象,将这个数组交给 composeNewsReply 来完成最终的XML ;下面是 composeTextReply 和 composeNewsReply 方法的代码。

private static String composeTextReply(ReceiveMsg msg, String strReply)  
{
    Datetime dt = System.now();
    String returnDT = dt.format('EEEE, MMMM d, yyyy');
    String replyMSG = '<xml><ToUserName><![CDATA[{0}]]></ToUserName><FromUserName><![CDATA[{1}]]></FromUserName><CreateTime>' + returnDT + '</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[{2}]]></Content></xml>';
    String[] arguments = new String[]{msg.fromUserName, msg.toUserName, strReply};
    return String.format(replyMSG, arguments);
}
private static String composeNewsReply(ReceiveMsg msg, List<ReplyMsg> newsList)  
{
    String strNews = '';
    String newsTpl = '<item><Title><![CDATA[{0}]]></Title><Description><![CDATA[{1}]]></Description><PicUrl><![CDATA[{2}]]></PicUrl><Url><![CDATA[{3}]]></Url></item>';
    for(ReplyMsg 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;
}

演示结果如下