微信将用户发送的消息分成两种,一种是普通消息,另一种是事件推送消息。其中普通消息又有8种类型,分别是文本,图片,语音,视频,小视频,地理位置,链接消息。

1 普通消息

当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。这句话对理解微信开发很重要,你还记得微信服务器什么时候会发送GET请求到URL上吗?没错,就是在服务器配置哪里。

微信服务器要么发get请求,要么发post请求给我的服务器,所以我的服务器中只需要分别重载HttpServlet的doGet和doPost方法即可,如下图所示:

java实现给微信好友发送消息功能 java操作微信_xml

doGet方法,用来验证是否正确接入微信服务器。
doPost方法,用来处理用户发来的请求。

2 消息交互流程图

这是一张微信官方的消息交互流程图,说明了开发者服务器接受消息的过程。

java实现给微信好友发送消息功能 java操作微信_xml_02

再配合下面这样更直观的图,相信你已经有所领悟了。

java实现给微信好友发送消息功能 java操作微信_xml_03

微信服务器与我的服务器之间的数据都需要二次加工的,即数据被包装成固定的 xml格式。

注意:![CDATA[ ]]>是什么意思?(由于我现在使用的markdown编辑器,!左边的小括号我写不出来,会被转义)

答案: ![CDATA[ ]]>里面的语句不会被解析器解析,防止语句中出现转义字符会被转义。

3 java代码实现text消息前后端交互案例(根据用户发送消息,回复消息)
3.1 重载的doPost方法:

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        String responseMessage = coreService.processRequest(req);//工具类 coreService的processRequest方法处理用户请求
        PrintWriter out = resp.getWriter();
        out.print(responseMessage);
        out.close();
    }

3.2 工具类coreServlet:

public class coreService {

    public static String processRequest(HttpServletRequest request) {
        String responseContent = "初始化信息";
        String responseMessage = "success";//ֱ保证微信服务器5秒内能接受到回复
        try {
            Map<String, String> map = messageUtil.xmlToMap(request);//利用写好的工具类将微信服务器发来的xml格式消息解析到map里
            //从map中拿到相应参数ֵ
            String fromUserName = map.get("FromUserName");
            String toUserName = map.get("ToUserName");
            String msgType = map.get("MsgType");
            System.out.println("用户发送的消息类型:"+msgType);
            if (messageUtil.resp_message_type_text.equals(msgType)) {//如果用户发送的是text类型的消息
                if ("A".equals(map.get("Content").toUpperCase())){
                    responseContent="模拟用户发送A后,服务器推送相应的内容";  
                }
                else if ("B".equals(map.get("Content").toUpperCase())) {
                    responseContent="模拟用户发送B后,服务器推送相应的内容";
                }
                else if ("?".equals(map.get("Content"))) {
                    responseContent="?让我不知错所";
                }
                else {
                    responseContent="请老老实实发送A,B或者英文格式的?";
                }
            }
            else if (messageUtil.resp_message_type_event.equals(msgType)) {//如果用户发送的是event类型的消息
                    System.out.println(map);
                if ("subscribe".equals(map.get("Event"))) {
                    responseContent="很荣幸,您订阅了此公众号!\n发送A,查看A菜单写信息。\n发送B,查看B菜单写信息。\n发送?,我们将指引你前行。";
                }
                else if ("unsubscribe".equals(map.get("Event"))) {
                    responseContent="很遗憾,你取消了本公众号!";
                }
            }

            //再拼装xml格式的返回消息,发送给微信服务器
            textMessage text = new textMessage();
            text.setFromUserName(toUserName);
            text.setToUserName(fromUserName);
            text.setCreateTime(new Date().getTime());
            text.setMsgType(messageUtil.resp_message_type_text);
            text.setContent(responseContent);
            System.out.println("消息接收方="+text.getToUserName()+",发送方="+text.getFromUserName()+",消息内容="+text.getContent());
            responseMessage = messageUtil.mapToXml(text);//利用写好的工具类将text类型消息拼装成微信服务器接受的xml格式
            System.out.println("回复给微信服务器的text消息:\n"+responseMessage);
        } 
        catch (Exception  e) {
            e.printStackTrace();
        }
        return responseMessage;
    }

}

3.3 工具类messageUtil

package zk.util;
import zk.entity.textMessage;
其他包省略,自行包入
public class messageUtil {
    public final static String resp_message_type_text = "text";
    public final static String resp_message_type_event = "event";
    public static Map<String, String> xmlToMap(HttpServletRequest request) throws  Exception {
        Map<String, String> map = new HashMap<String,String>();
        InputStream inputStream = request.getInputStream();
        SAXReader reader = new SAXReader();
        Document read = reader.read(inputStream);
        Element rootElement = read.getRootElement();
        List<Element> elements = rootElement.elements();
        System.out.println("*******************************");
        for (Element element : elements) {
            System.out.println(element.getName()+":"+element.getText());
            map.put(element.getName(), element.getText());
        }
        System.out.println("*******************************");
        inputStream.close();
        return map;
    }

    public static String mapToXml(textMessage text){
        XStream stream = new XStream();
        System.out.println(stream.toXML(text));//全类名<zk.entity.textMessage>
        stream.alias("xml",text.getClass());//首尾全类名改成<xml>
        return stream.toXML(text);
    }

}

注意
mapToXml方法,stream.toXML(text)的输出结果格式为:

java实现给微信好友发送消息功能 java操作微信_服务器_04

修改类型别名stream.alias(“xml”,text.getClass())后的输出格式才能被微信服务器识别:

java实现给微信好友发送消息功能 java操作微信_服务器_05

4 测试text类型消息

1)开启natapp.exe

java实现给微信好友发送消息功能 java操作微信_xml_06

2)开启后台服务器(Tomcat)

java实现给微信好友发送消息功能 java操作微信_服务器_07

3)手机微信关注测试公众号之后给公众号发送text消息

java实现给微信好友发送消息功能 java操作微信_xml_08

java实现给微信好友发送消息功能 java操作微信_xml_09

java实现给微信好友发送消息功能 java操作微信_服务器_10

java实现给微信好友发送消息功能 java操作微信_服务器_11