How can Spring Boot return messages to WeChat public address?

hello, ladies and gentlemen, today we will continue to learn how to develop WeChat public numbers through Spring Boot. For those who haven't read the previous article, it's suggested to read the above to help understand this article:

In the previous article, we have connected wechat server with our own server, and we can also receive messages from wechat server on our own server. In this article, we want to see how to reply messages to wechat server.

Message classification

Before discussing how to reply to wechat server, we need to first understand the main types of messages sent by wechat server and the types of messages we reply to wechat.

As you have learned above, there is a MsgType field in the xml message sent by wechat, which is used to mark the message type. This type can mark whether this message is a normal message or an event message or a graphic message.

General information mainly refers to:

  • Text message
  • Picture message
  • Voice message
  • Video message
  • Small video message
  • Address location message
  • Link message

Different message types correspond to different msgtypes. Here I take ordinary messages as an example, as follows:

Message type MsgType
Text message text
Picture message image
Voice message voice
Video message video
Small video message shortvideo
Address location message location
Link message link

We should not think that the format of different types of messages is the same, but actually they are different. That is to say, the message with MsgType of text and the message with MsgType of image sent to us by wechat server are different, which brings about a problem that I can't use a Bean to receive different types of data, so we usually use Map here Just receive it.

This is the reception of messages. In addition to the reception of messages, there is also a message reply. There are many types of messages we reply to. We can reply to ordinary messages, picture messages, voice messages, etc. different reply messages can be encapsulated accordingly. Because different return message instances also have some common properties, such as who sent the message, who sent it, message type, message id, etc., we can define these common properties as a parent class, and then different messages inherit the parent class.

Return message type definition

First, let's define a public message type:

public class BaseMessage {
    private String ToUserName;
    private String FromUserName;
    private long CreateTime;
    private String MsgType;
    private long MsgId;
    //Omit getter/setter
}

Ad locum:

  • ToUserName indicates the developer's wechat
  • FromUserName indicates the sender account (user's OpenID)
  • Creation time of CreateTime message
  • MsgType indicates the type of message
  • MsgId means message id

This is our basic message type. That is to say, no matter what type of message we return to the user, there are these basic properties. Then on this basis, we expand the text message, picture message and so on.

Let's look at the definition of text messages:

public class TextMessage extends BaseMessage {
    private String Content;
    //Omit getter/setter
}

The text message has a Content attribute on the basis of the previous message, so the text message inherits from the BaseMessage, and an additional Content attribute can be added.

Other message types have similar definitions. I won't list them one by one. As for the format of other messages, you can refer to wechat open documents( http://1t.click/aPXK).

Return message generation

After defining the Bean of message type, the next step is to generate XML from entity class.

First, we define a message tool class to enumerate common message types:

/**
 * Return message type: Text
 */
public static final String RESP_MESSAGE_TYPE_TEXT = "text";
/**
 * Return message type: Music
 */
public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
/**
 * Return message type: Text
 */
public static final String RESP_MESSAGE_TYPE_NEWS = "news";
/**
 * Return message type: picture
 */
public static final String RESP_MESSAGE_TYPE_Image = "image";
/**
 * Return message type: voice
 */
public static final String RESP_MESSAGE_TYPE_Voice = "voice";
/**
 * Return message type: Video
 */
public static final String RESP_MESSAGE_TYPE_Video = "video";
/**
 * Request message type: Text
 */
public static final String REQ_MESSAGE_TYPE_TEXT = "text";
/**
 * Request message type: picture
 */
public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
/**
 * Request message type: link
 */
public static final String REQ_MESSAGE_TYPE_LINK = "link";
/**
 * Request message type: geographic location
 */
public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
/**
 * Request message type: Audio
 */
public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
/**
 * Request message type: Video
 */
public static final String REQ_MESSAGE_TYPE_VIDEO = "video";
/**
 * Request message type: push
 */
public static final String REQ_MESSAGE_TYPE_EVENT = "event";
/**
 * Event type: Subscribe
 */
public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
/**
 * Event type: unsubscribe
 */
public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
/**
 * Event type: click (custom menu click event)
 */
public static final String EVENT_TYPE_CLICK = "CLICK";
/**
 * Event type: view (custom menu URl view)
 */
public static final String EVENT_TYPE_VIEW = "VIEW";
/**
 * Event type: Location
 */
public static final String EVENT_TYPE_LOCATION = "LOCATION";
/**
 * Event type: Location
 */
public static final String EVENT_TYPE_SCAN = "SCAN";

Note the definition of message type here. The message type starting with RESP indicates the returned message type, and the message type sent by wechat server is REQ. Then define two more methods in this tool class to convert the returned object into XML:

public static String textMessageToXml(TextMessage textMessage) {
    xstream.alias("xml", textMessage.getClass());
    return xstream.toXML(textMessage);
}
private static XStream xstream = new XStream(new XppDriver() {
    public HierarchicalStreamWriter createWriter(Writer out) {
        return new PrettyPrintWriter(out) {
            boolean cdata = true;
            @SuppressWarnings("rawtypes")
            public void startNode(String name, Class clazz) {
                super.startNode(name, clazz);
            }
            protected void writeText(QuickWriter writer, String text) {
                if (cdata) {
                    writer.write("<![CDATA[");
                    writer.write(text);
                    writer.write("]]>");
                } else {
                    writer.write(text);
                }
            }
        };
    }
});

textMessageToXML method is used to convert TextMessage object into XML and return it to wechat server. For similar methods, we need to define imageMessageToXml, voiceMessageToXml, etc., but the definitions are basically similar, so I will not list them one by one.

Return to message distribution

Because messages sent by users may have many situations, we need to classify them for processing, which involves the distribution of returned messages. So here I define another tool class to return message distribution, as follows:

public class MessageDispatcher {
    public static String processMessage(Map<String, String> map) {
        String openid = map.get("FromUserName"); //User openid
        String mpid = map.get("ToUserName");   //Public number original ID
        if (map.get("MsgType").equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) { 
            //Normal text message
            TextMessage txtmsg = new TextMessage();
            txtmsg.setToUserName(openid);
            txtmsg.setFromUserName(mpid);
            txtmsg.setCreateTime(new Date().getTime());
            txtmsg.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
            txtmsg.setContent("This is the return message");
            return MessageUtil.textMessageToXml(txtmsg);
        }
        return null;
    }
    public String processEvent(Map<String, String> map) {
        //Handle events here
    }
}

Here we can add a few else if to judge different message types. I only have ordinary text messages here, so one if is enough.

I'm dead about the return value here. Actually, I need to query in the data according to the Content from the wechat server, and return the query result. I'm sure you can handle the database query. I won't introduce it again here.

Finally, call the method in message receiving Controller, which is as follows:

@PostMapping(value = "/verify_wx_token",produces = "application/xml;charset=utf-8")
public String handler(HttpServletRequest request, HttpServletResponse response) throws Exception {
    request.setCharacterEncoding("UTF-8");
    Map<String, String> map = MessageUtil.parseXml(request);
    String msgType = map.get("MsgType");
    if (MessageUtil.REQ_MESSAGE_TYPE_EVENT.equals(msgType)) {
        return messageDispatcher.processEvent(map);
    }else{
        return messageDispatcher.processMessage(map);
    }
}

In the Controller, we first determine whether the message is an event. If it is an event, enter the event processing channel. If it is not an event, enter the message processing channel.

Note that the return message code needs to be configured here, otherwise the Chinese code may appear.

After that, our server will be able to return the message to the public address.

After the last article was sent out, a little friend asked song if it would be open-source. I can tell you responsibly that it will be open-source. After the series is finalized, I will upload the code to GitHub after processing.

OK, let's talk about this first.

Pay attention to the public number [Jiangnan rain], focus on Spring Boot+ micro service and front end separation and other full stack technology, regular video tutorial sharing, focus on back to Java, receive Pine's carefully prepared Java dry goods for you!

Tags: Java xml Spring Attribute

Posted on Wed, 06 Nov 2019 22:23:38 -0500 by brash