一旦手把手教你开发微信公众平台2

目录:

  • 前言
  • 回顾
  • 本节内容
  • 准备工作
  • 开发喽
    • 公共部分
    • 微信服务器发送的xml解析weChatUtils编写
    • 控制器编写
    • 实体补全
  • 总结

前言

最近忙于毕业设计,更新慢,希望大家见谅。

回顾

上一节我讲了如何申请微信公众平台测试账号、配置接口信息、搭建了开发环境,并且初步实现了微信服务器消息的验证。

本节内容

  • 实现了微信的消息验证之后,需要注意的是,每次微信服务器发送消息过来的时候,我们都需要进行验证,避免有不法分子冒充微信平台恶意发送消息。
  • 本节将会继续讲解,主要内容是消息接收。

准备工作

  • 这里我给大家列出几个工具类,这些工具类是我个人编写的,应该不是很难,所以不会讲解,只是给大家贴个代码:
  • jacksonUtils:json解析工具(工具类以及精简,比较复杂的方法也用不到)
package com.yd.app.utils;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * @Author 一旦
 * @Time 2014-*-*
 */
@SuppressWarnings("unchecked")
public class JacksonUtils {

    private static ObjectMapper objectMapper = null;

    static {
        objectMapper = new ObjectMapper();
    }

    /*
     * Write Object To Json
     */

    public static String writeObject2Json(Object o) throws JsonGenerationException, JsonMappingException, IOException {
        return objectMapper.writeValueAsString(o);
    }

    public static String writeEntity2Json(Object o) throws JsonGenerationException, JsonMappingException, IOException {
        return objectMapper.writeValueAsString(o);
    }

    public static String writeMap2Json(Map<String, Object> map) throws JsonGenerationException, JsonMappingException, IOException {
        return objectMapper.writeValueAsString(map);
    }

    public static String writeList2Json(List<?> list) throws JsonGenerationException, JsonMappingException, IOException {
        return objectMapper.writeValueAsString(list);
    }

    /*
     * Read Json To Object
     */

    public static <T> T readJson2ObjectFromString(String jsonStr, Class<?> clazz) throws JsonParseException, JsonMappingException, IOException {
        return (T) objectMapper.readValue(jsonStr, clazz);
    }

    public static <T> T readJson2ObjectFromStream(InputStream inputStream, Class<?> clazz) throws JsonParseException, JsonMappingException, IOException {
        return (T) objectMapper.readValue(inputStream, clazz);
    }

    public static <T> T readJson2ObjectFromByteArray(byte[] bytes, Class<?> clazz) throws JsonParseException, JsonMappingException, IOException {
        return (T) objectMapper.readValue(bytes, 0, bytes.length, clazz);
    }

}
  • xmlUtils:xml操作工具(xstream封装,并且所以方法已经针对微信开发进行了特定优化)
package com.yd.wechat.utils;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.io.xml.Dom4JDriver;

public class XmlUtils {

    /**
     * 获取只有一层次的xml文档,无属性。 转换为map。
     * */
    public static Map<String, String> xml2Map(InputStream in) {

        Map<String, String> map = new HashMap<String, String>();

        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(in);

            Element root = document.getRootElement();
            List<Element> elements = root.elements();

            for (Element e : elements) {
                map.put(e.getName(), e.getText());
            }

            return map;

        } catch (DocumentException e) {
            e.printStackTrace();
        }

        return null;

    }

    public static String object2Xml(Object object) {
        try {
            XStream xstream = new XStream(new Dom4JDriver());
            return xstream.toXML(object);
        } catch (Exception e) {
        }
        return null;
    }

    public static String object2Xml(Object object, String alias) {
        try {
            XStream xstream = new XStream(new Dom4JDriver());
            if (alias != null)
                xstream.alias(alias, object.getClass());
            else
                xstream.alias(object.getClass().getSimpleName(), object.getClass());
            return xstream.toXML(object);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /***
     * 如果alias不为空,由调用者决定别名。 否则,默认只为object对象指定一个别名为其类的简单名字。
     */
    public static String object2Xml(Object object, Map<String, Class<?>> alias) {
        try {
            XStream xstream = new XStream(new Dom4JDriver());

            if (alias != null) {
                for (Map.Entry<String, Class<?>> entry : alias.entrySet()) {
                    xstream.alias(entry.getKey(), entry.getValue());
                }
            } else {
                xstream.alias(object.getClass().getSimpleName(), object.getClass());
            }

            return xstream.toXML(object);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T xml2Object(String xml) {
        try {
            XStream xstream = new XStream(new Dom4JDriver());
            xstream.ignoreUnknownElements();
            return (T) xstream.fromXML(xml);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T xml2Object(String xml, Class<?> clazz) {
        try {
            XStream xstream = new XStream(new Dom4JDriver());
            xstream.alias(clazz.getSimpleName(), clazz);
            xstream.ignoreUnknownElements();
            return (T) xstream.fromXML(xml);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T xml2Object(String xml, Class<?> clazz, String alias) {
        try {
            XStream xstream = new XStream(new Dom4JDriver());
            xstream.alias(alias, clazz);
            xstream.ignoreUnknownElements();
            return (T) xstream.fromXML(xml);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T xml2Object(String xml, Class<?> clazz, String alias, List<Converter> converters) {
        try {
            XStream xstream = new XStream(new Dom4JDriver());
            xstream.alias(alias, clazz);
            xstream.ignoreUnknownElements();

            if (converters != null && converters.size() > 0) {
                for (Converter converter : converters) {
                    xstream.registerConverter(converter);
                }
            }

            return (T) xstream.fromXML(xml);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}

开发喽

公共部分

  • 本人写了几个公用类,下面列代码:
  • Message类(公用的接受消息父类)
package com.yd.wechat.message.common;

public class Message {

    protected MessageBody messageBody;

    public Message(MessageBody messageBody) {
        super();
        this.messageBody = messageBody;
    }

    /*******************************************************************************************************/
    /** 提供消息类型的判断的方法 ***********************************************************************************/
    public boolean isTextMessage() {
        return MessageType.text.toString().equalsIgnoreCase(messageBody.MsgType);
    }

    public boolean isImageMessage() {
        return MessageType.image.toString().equalsIgnoreCase(messageBody.MsgType);
    }

    public boolean isVoiceMessage() {
        return MessageType.voice.toString().equalsIgnoreCase(messageBody.MsgType);
    }

    public boolean isVideoMessage() {
        return MessageType.video.toString().equalsIgnoreCase(messageBody.MsgType);
    }

    public boolean isShortVideoMessage() {
        return MessageType.shortvideo.toString().equalsIgnoreCase(messageBody.MsgType);
    }

    public boolean isLocationMessage() {
        return MessageType.location.toString().equalsIgnoreCase(messageBody.MsgType);
    }

    public boolean isLinkMessage() {
        return MessageType.link.toString().equalsIgnoreCase(messageBody.MsgType);
    }

    public boolean isEventMessage() {
        return MessageType.event.toString().equalsIgnoreCase(messageBody.MsgType);
    }

    public boolean isSubscribeEvent() {
        return isEventMessage() && EventType.subscribe.toString().equalsIgnoreCase(messageBody.Event) && messageBody.EventKey == null;
    }

    public boolean isUnSubscribeEvent() {
        return isEventMessage() && EventType.unsubscribe.toString().equalsIgnoreCase(messageBody.Event);
    }

    public boolean isSubscribeScanEvent() {
        return isEventMessage() && EventType.subscribe.toString().equalsIgnoreCase(messageBody.Event) && messageBody.EventKey != null;
    }

    public boolean isScanEvent() {
        return isEventMessage() && EventType.SCAN.toString().equalsIgnoreCase(messageBody.Event);
    }

    public boolean isLocationEvent() {
        return isEventMessage() && EventType.LOCATION.toString().equalsIgnoreCase(messageBody.Event);
    }

    public boolean isClickEvent() {
        return isEventMessage() && EventType.CLICK.toString().equalsIgnoreCase(messageBody.Event);
    }

    public boolean isViewEvent() {
        return isEventMessage() && EventType.VIEW.toString().equalsIgnoreCase(messageBody.Event);
    }

    /*******************************************************************************************************/

    /** 提供消息公共字段的get和set方法 */
    public String getFromUserName() {
        return messageBody.FromUserName;
    }

    public void setFromUserName(String fromUserName) {
        messageBody.FromUserName = fromUserName;
    }

    public String getToUserName() {
        return messageBody.ToUserName;
    }

    public void setToUserName(String toUserName) {
        messageBody.ToUserName = toUserName;
    }

    public Long getCreateTime() {
        return messageBody.CreateTime;
    }

    public void setCreateTime(Long createTime) {
        messageBody.CreateTime = createTime;
    }

    public String getMsgType() {
        return messageBody.MsgType;
    }

    public void setMsgType(String msgType) {
        messageBody.MsgType = msgType;
    }

    /** 提供protected类型的get和set方法 */

    protected String getMsgId() {
        return messageBody.MsgId;
    }

    protected void setMsgId(String msgId) {
        messageBody.MsgId = msgId;
    }

    protected String getContent() {
        return messageBody.Content;
    }

    protected void setContent(String content) {
        messageBody.Content = content;
    }

    public String getPicUrl() {
        return messageBody.PicUrl;
    }

    public void setPicUrl(String picUrl) {
        messageBody.PicUrl = picUrl;
    }

    public String getMediaId() {
        return messageBody.MediaId;
    }

    public void setMediaId(String mediaId) {
        messageBody.MediaId = mediaId;
    }

    public String getFormat() {
        return messageBody.Format;
    }

    public void setFormat(String format) {
        messageBody.Format = format;
    }

    public String getThumbMediaId() {
        return messageBody.ThumbMediaId;
    }

    public void setThumbMediaId(String thumbMediaId) {
        messageBody.ThumbMediaId = thumbMediaId;
    }

    public String getTitle() {
        return messageBody.Title;
    }

    public void setTitle(String title) {
        messageBody.Title = title;
    }

    public String getDescription() {
        return messageBody.Description;
    }

    public void setDescription(String description) {
        messageBody.Description = description;
    }

    public String getUrl() {
        return messageBody.Url;
    }

    public void setUrl(String url) {
        messageBody.Url = url;
    }

    public String getLocation_X() {
        return messageBody.Location_X;
    }

    public void setLocation_X(String location_X) {
        messageBody.Location_X = location_X;
    }

    public String getLocation_Y() {
        return messageBody.Location_Y;
    }

    public void setLocation_Y(String location_Y) {
        messageBody.Location_Y = location_Y;
    }

    public String getScale() {
        return messageBody.Scale;
    }

    public void setScale(String scale) {
        messageBody.Scale = scale;
    }

    public String getLabel() {
        return messageBody.Label;
    }

    public void setLabel(String label) {
        messageBody.Label = label;
    }

    public String getEvent() {
        return messageBody.Event;
    }

    public void setEvent(String event) {
        messageBody.Event = event;
    }

    public String getEventKey() {
        return messageBody.EventKey;
    }

    public void setEventKey(String eventKey) {
        messageBody.EventKey = eventKey;
    }

    public String getTicket() {
        return messageBody.Ticket;
    }

    public void setTicket(String ticket) {
        messageBody.Ticket = ticket;
    }

    public Double getLatitude() {
        return messageBody.Latitude;
    }

    public void setLatitude(Double latitude) {
        messageBody.Latitude = latitude;
    }

    public Double getLongitude() {
        return messageBody.Longitude;
    }

    public void setLongitude(Double longitude) {
        messageBody.Longitude = longitude;
    }

    public Double getPrecision() {
        return messageBody.Precision;
    }

    public void setPrecision(Double precision) {
        messageBody.Precision = precision;
    }

}
  • MessageBody:(真正放xml属性的地方,之所以有这个类,具体解释见代码中。简单的说,实用继承的方式需要解析xml俩次,实用聚合方式只解析一次)
package com.yd.wechat.message.common;

/**
 * @title 这个类用于接收所有的消息。
 * @desc 经过本人考虑,多次修改,发现,很多消息类似,但也有区别。
 * @desc 1可以采用一个实体表示,会有很多冗余属性,而且可能会误操作。
 * @desc (操作了不属于当前类型的字段,这种情况会报 nullpointer 异常)
 * @desc 2也可以分开。
 * @desc 3还可以公用一部分,分开一部分。(继承)
 * @desc 最初本人想采用3的方式,后来发现越来越多的需要提前字段的字段,于是越来越多字段要提到公用的实体中。
 * @desc 而且,每次都必须先解析为公用实体,判断类型之后再解析为具体类型。
 * @desc 于是,最终修改为采用1个实体表示。
 * @desc 但是仍然使用许多具体的实体,用于提供get和set方法,这样控制了不同类型对不同字段的访问权限。
 */
public class MessageBody {

    /** 每个消息都带有的字段,在本类提供了get/set方法 */
    protected String FromUserName;
    protected String ToUserName;
    protected Long CreateTime;
    protected String MsgType;

    protected String MsgId;
    protected String Content;
    protected String PicUrl;
    protected String MediaId;
    protected String Format;
    protected String ThumbMediaId;
    protected String Title;
    protected String Description;
    protected String Url;
    protected String Event;
    protected String EventKey;
    protected String Ticket;
    protected String Location_X;
    protected String Location_Y;
    protected String Scale;
    protected String Label;
    protected Double Latitude;
    protected Double Longitude;
    protected Double Precision;

    /*******************************************************************************************************/
    /** 提供消息类型的判断的方法 ***********************************************************************************/
    public boolean isTextMessage() {
        return MessageType.text.toString().equalsIgnoreCase(this.MsgType);
    }

    public boolean isImageMessage() {
        return MessageType.image.toString().equalsIgnoreCase(this.MsgType);
    }

    public boolean isVoiceMessage() {
        return MessageType.voice.toString().equalsIgnoreCase(this.MsgType);
    }

    public boolean isVideoMessage() {
        return MessageType.video.toString().equalsIgnoreCase(this.MsgType);
    }

    public boolean isShortVideoMessage() {
        return MessageType.shortvideo.toString().equalsIgnoreCase(this.MsgType);
    }

    public boolean isLocationMessage() {
        return MessageType.location.toString().equalsIgnoreCase(this.MsgType);
    }

    public boolean isLinkMessage() {
        return MessageType.link.toString().equalsIgnoreCase(this.MsgType);
    }

    public boolean isEventMessage() {
        return MessageType.event.toString().equalsIgnoreCase(this.MsgType);
    }

    public boolean isSubscribeEvent() {
        return isEventMessage() && EventType.subscribe.toString().equalsIgnoreCase(this.Event) && this.EventKey == null;
    }

    public boolean isUnSubscribeEvent() {
        return isEventMessage() && EventType.unsubscribe.toString().equalsIgnoreCase(this.Event);
    }

    public boolean isSubscribeScanEvent() {
        return isEventMessage() && EventType.subscribe.toString().equalsIgnoreCase(this.Event) && this.EventKey != null;
    }

    public boolean isScanEvent() {
        return isEventMessage() && EventType.SCAN.toString().equalsIgnoreCase(this.Event);
    }

    public boolean isLocationEvent() {
        return isEventMessage() && EventType.LOCATION.toString().equalsIgnoreCase(this.Event);
    }

    public boolean isClickEvent() {
        return isEventMessage() && EventType.CLICK.toString().equalsIgnoreCase(this.Event);
    }

    public boolean isViewEvent() {
        return isEventMessage() && EventType.VIEW.toString().equalsIgnoreCase(this.Event);
    }

    /*******************************************************************************************************/

}
  • MessageType(不多说,消息类型嘛)
package com.yd.wechat.message.common;

public enum MessageType {

    text,image,voice,video,shortvideo,location,link,

    event,

    music,news

}

微信服务器发送的xml解析(weChatUtils编写)

  • 本节的weChatUtils上一节一节贴代码,只不过当时精简过了,这节下面贴一个完整的。代码中有解释,大家仔细看都能明白的。
package com.yd.wechat.core;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.xml.bind.annotation.adapters.HexBinaryAdapter;

import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.yd.wechat.message.common.Message;
import com.yd.wechat.message.common.MessageBody;
import com.yd.wechat.message.event.ClickEventMessage;
import com.yd.wechat.message.event.LocationEventMessage;
import com.yd.wechat.message.event.ScanEventMessage;
import com.yd.wechat.message.event.SubscribeEventMessage;
import com.yd.wechat.message.event.SubscribeScanEventMessage;
import com.yd.wechat.message.event.UnSubscribeEventMessage;
import com.yd.wechat.message.event.ViewEventMessage;
import com.yd.wechat.message.normal.ImageMessage;
import com.yd.wechat.message.normal.LinkMessage;
import com.yd.wechat.message.normal.LocationMessage;
import com.yd.wechat.message.normal.ShortVideoMessage;
import com.yd.wechat.message.normal.TextMessage;
import com.yd.wechat.message.normal.VideoMessage;
import com.yd.wechat.message.normal.VoiceMessage;
import com.yd.wechat.utils.XmlUtils;

public class WeChatUtils {

    private static final String token = "hello";

    public static Boolean checkSignature(String signature, String timestamp, String nonce) {
        //sort
        String[] arr = new String[] { token, timestamp, nonce };
        Arrays.sort(arr);
        StringBuffer sf = new StringBuffer();
        for (int i = 0; i < arr.length; i++) {
            sf.append(arr[i]);
        }
        //sha1加密
        MessageDigest md;
        try {
            md = MessageDigest.getInstance("SHA");
            // 执行摘要方法
            byte[] digest = md.digest(sf.toString().getBytes());
            String encriptStr = new HexBinaryAdapter().marshal(digest);
            if (encriptStr.equalsIgnoreCase(signature)) {
                return true;
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 消息解析步骤1:
     * @param xmlContent 要解析的xml字符串
     */
    public static Message parseMessage(String xmlContent) {
        if (xmlContent == null)
            return null;
        List<Converter> converters = new ArrayList<Converter>();
        converters.add(new Converter() {
            @Override
            public boolean canConvert(Class clazz) {
                if (clazz.equals(Double.class))
                    return true;
                return false;
            }

            @Override
            public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
                if (reader.getValue() != null && !reader.getValue().isEmpty()) {
                    /** 如果不满足条件直接返回null,如果转换过程出现异常也直接返回null。 */
                    /** 注意这里这么做的原因是,Double类型转换的时候如果是空字符串会报错,导致整个xml转换出错。 */
                    try {
                        Double ret = Double.parseDouble(reader.getValue());
                        return ret;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return null;
            }

            @Override
            public void marshal(Object obj, HierarchicalStreamWriter writer, MarshallingContext context) {

            }
        });
        converters.add(new Converter() {
            @Override
            public boolean canConvert(Class clazz) {
                if (clazz.equals(Long.class))
                    return true;
                return false;
            }

            @Override
            public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
                if (reader.getValue() != null && !reader.getValue().isEmpty()) {
                    /** 如果不满足条件直接返回null,如果转换过程出现异常也直接返回null。 */
                    /** 注意这里这么做的原因是,Double类型转换的时候如果是空字符串会报错,导致整个xml转换出错。 */
                    try {
                        Long ret = Long.parseLong(reader.getValue());
                        return ret;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return null;
            }

            @Override
            public void marshal(Object obj, HierarchicalStreamWriter writer, MarshallingContext context) {

            }
        });
        MessageBody messageBody = XmlUtils.xml2Object(xmlContent, MessageBody.class, "xml", converters);
        if (messageBody == null)
            return null;
        return parseMessage(messageBody, xmlContent);
    }

    /***
     * 消息解析步骤2:
     * 如果能够识别类型,则返回一个具体的类型。 否则返回原始Message即可。
     *
     * @param messageBody 待识别的message。
     * @param xmlContent 原始xml数据。
     * @return 如果能够识别类型,则返回一个具体的类型。 否则返回原始Message即可。
     */
    public static Message parseMessage(MessageBody messageBody, String xmlContent) {
        /** 文本消息 */
        if (messageBody.isTextMessage()) {
            return new TextMessage(messageBody);
        } else if (messageBody.isImageMessage()) {
            return new ImageMessage(messageBody);
        } else if (messageBody.isVoiceMessage()) {
            return new VoiceMessage(messageBody);
        } else if (messageBody.isVideoMessage()) {
            return new VideoMessage(messageBody);
        } else if (messageBody.isShortVideoMessage()) {
            return new ShortVideoMessage(messageBody);
        } else if (messageBody.isLocationMessage()) {
            return new LocationMessage(messageBody);
        } else if (messageBody.isLinkMessage()) {
            return new LinkMessage(messageBody);
        } else if (messageBody.isSubscribeEvent()) {
            return new SubscribeEventMessage(messageBody);
        } else if (messageBody.isUnSubscribeEvent()) {
            return new UnSubscribeEventMessage(messageBody);
        } else if (messageBody.isSubscribeScanEvent()) {
            return new SubscribeScanEventMessage(messageBody);
        } else if (messageBody.isScanEvent()) {
            return new ScanEventMessage(messageBody);
        } else if (messageBody.isLocationEvent()) {
            return new LocationEventMessage(messageBody);
        } else if (messageBody.isClickEvent()) {
            return new ClickEventMessage(messageBody);
        } else if (messageBody.isViewEvent()) {
            return new ViewEventMessage(messageBody);
        }

        /** 如果不符合任何的类型,则直接构造一个Message返回。 */
        return new Message(messageBody);
    }

}

控制器编写

  • 依然是HelloController,不好意思,实在不喜欢精简代码了,部分关于回复的是之后的内容,大家先简单看吧,看不懂就略过以后看。
  • 还有一点注意:关于回复消息的代码有些注释掉的代码以及关于视频回复部分暂时还有待完善,有些问题。所以如果想学习回复的请以后看我继续更新吧。
@RequestMapping(value = "/accept.do", method = RequestMethod.POST)
    @ResponseBody
    public String acceptContentMessage(@RequestBody String xmlContent) {
        try {
            xmlContent = new String(xmlContent.getBytes("ISO8859-1"), "utf-8");
            System.out.println("===========>>>msg is<<<===========");
            System.out.println(xmlContent);
            System.out.println("===========>>>msg end<<<===========");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        String ans = "";

        Message message = WeChatUtils.parseMessage(xmlContent);
        if (message == null) {
            ans = "message is null";
        } else if (message.isTextMessage()) {

            TextMessage textMessage = (TextMessage) message;
            String content = textMessage.getContent();
            if ("music".equalsIgnoreCase(content)) {
                //return MusicMessage
                String musicURL = url + "res/music/test.mp3";
                String HQmusicURL = url + "res/music/test.mp3";
                System.out.println(new MusicReply(message, "title", "desc", musicURL, HQmusicURL, null).toString());
                return new MusicReply(message, "title", "desc", musicURL, HQmusicURL, null).toString();
            } else if ("news".equalsIgnoreCase(content)) {
                //return news message
                NewsReply newsReply = new NewsReply(message);
                newsReply.addNewsItem("titleA", "descriptionA", url + "res/img/icon1.png", "http://www.baidu.com");
                newsReply.addNewsItem("titleB", "descriptionB", url + "res/img/icon2.png", "http://www.baidu.com");
                newsReply.addNewsItem("titleC", "descriptionC", url + "res/img/icon3.png", "http://www.baidu.com");
                newsReply.addNewsItem("titleD", "descriptionD", url + "res/img/icon4.png", "http://www.baidu.com");
                System.out.println(newsReply.toString());
                return newsReply.toString();
            } else {
                //return textMessage
                return new TextReply(textMessage, "" + textMessage.getContent()).toString();
            }
        } else if (message.isImageMessage()) {
            ImageMessage imageMessage = (ImageMessage) message;

            System.out.println("===========>>>reply is<<<===========");
            System.out.println(new ImageReply(imageMessage, imageMessage.getMediaId()).toString());
            System.out.println("============>>>>reply end<<<===========");

            return new ImageReply(imageMessage, imageMessage.getMediaId()).toString();

        } else if (message.isVoiceMessage()) {
            VoiceMessage voiceMessage = (VoiceMessage) message;
            System.out.println("===========>>>reply is<<<===========");
            System.out.println(new VoiceReply(voiceMessage, voiceMessage.getMediaId()).toString());
            System.out.println("============>>>>reply end<<<===========");
            return new VoiceReply(voiceMessage, voiceMessage.getMediaId()).toString();
        } else if (message.isVideoMessage()) {

            VideoMessage videoMessage = (VideoMessage) message;

            System.out.println("===========>>>reply is<<<===========");

            System.out.println(new VideoReply(videoMessage, videoMessage.getMediaId(), "replyTitle", "replyDescription").toString());

            System.out.println("============>>>>reply end<<<===========");

            return new VideoReply(videoMessage, videoMessage.getMediaId(), "replyTitle", "replyDescription").toString();

            //          return "<?xml version=\"1.0\" encoding=\"ISO8859-1\"?>"+
            //          "<xml>"+
            //          "<FromUserName>gh_0d0dbff95290</FromUserName>"+
            //          "<ToUserName>oSUj2so2rsxPrDLy3IThmNd5-r8Q</ToUserName>"+
            //          "<CreateTime>1430112520511</CreateTime>"+
            //          "<MsgType>video</MsgType>"+
            //          "  <Video>"+
            //          "    <MediaId><![CDATA["+ videoMessage.getMediaId() +"]]</MediaId>"+
            //          "    <Title><![CDATA[replyTitle]]></Title>"+
            //          "    <Description>replyDescription</Description>"+
            //          "  </Video>"+
            //          "</xml>";

//                      return "<xml>"+
//                      "<ToUserName><![CDATA[oSUj2so2rsxPrDLy3IThmNd5-r8Q]]></ToUserName>"+
//                      "<FromUserName><![CDATA[gh_0d0dbff95290]]></FromUserName>"+
//                      "<CreateTime>12345678</CreateTime>"+
//                      "<MsgType><![CDATA[video]]></MsgType>"+
//                      "<Video>"+
//                      "<MediaId><![CDATA[TM6A2Prf1Q19XolT7S0gr4oduh1paHT72i0QJ6Xt0H2SkYwgSNsp-C641w-FjC1U]]></MediaId>"+
//                      "<Title><![CDATA[replyTitle]]></Title>"+
//                      "<Description><![CDATA[replyDescription]]></Description>"+
//                      "</Video> "+
//                      "</xml>";

        } else if (message.isShortVideoMessage()) {
            ShortVideoMessage shortVideoMessage = (ShortVideoMessage) message;
            ans = "this is an shortVideoMessage";
        } else if (message.isLocationMessage()) {
            LocationMessage locationMessage = (LocationMessage) message;
            ans = "this is an locationMessage";
        } else if (message.isLinkMessage()) {
            LinkMessage linkMessage = (LinkMessage) message;
            ans = "this is an linkMessage";
        }
        /** event begin */
        else if (message.isSubscribeEvent()) {
            SubscribeEventMessage subscribeMessage = (SubscribeEventMessage) message;
            ans = "this is an subscribeMessage";
        } else if (message.isUnSubscribeEvent()) {
            UnSubscribeEventMessage unSubscribeMessage = (UnSubscribeEventMessage) message;
            ans = "this is an unSubscribeMessage";
        } else if (message.isSubscribeScanEvent()) {
            SubscribeScanEventMessage subscribeScanMessage = (SubscribeScanEventMessage) message;
            ans = "this is an subscribe subscribe scan Message";
        } else if (message.isScanEvent()) {
            ScanEventMessage scanMessage = (ScanEventMessage) message;
            ans = "this is an Scan Message";
        } else if (message.isClickEvent()) {
            ClickEventMessage clickMessage = (ClickEventMessage) message;
            ans = "this is an click Message";
        } else if (message.isViewEvent()) {
            ViewEventMessage viewMessage = (ViewEventMessage) message;
            ans = "this is an view Message";
        } else {
            ans = "this is an unknown message";
        }

        return "success";
    }

    /**
     * @desc 用户未关注时,进行关注后的事件推送
     *
     * @param ToUserName 开发者微信号
     * @param FromUserName 发送方帐号(一个OpenID)
     * @param CreateTime 消息创建时间 (整型)
     * @param MsgType 消息类型,event
     * @param Event 事件类型,subscribe
     * @param EventKey 事件KEY值,qrscene_为前缀,后面为二维码的参数值
     * @param Ticket 二维码的ticket,可用来换取二维码图片
     */
    //  public void subscribe() {
    //  }
}

实体补全

  • 大家应该发现我用了好多封装的消息实体,下面都给大家列出来:
  • TextMessage
package com.yd.wechat.message.normal;

import com.yd.wechat.message.common.Message;
import com.yd.wechat.message.common.MessageBody;

/***
 * 文本消息
 *
 * @author 一旦
 * @param ToUserName 开发者微信号
 * @param FromUserName 发送方帐号(一个OpenID)
 * @param CreateTime 消息创建时间 (整型)
 * @param MsgType text
 * @param Content 文本消息内容
 * @param MsgId 消息id,64位整型
 */
public class TextMessage extends Message {

    //  protected String MsgId;
    //  protected String Content;

    public TextMessage(MessageBody messageBody) {
        super(messageBody);
    }

    public String getMsgId() {
        return super.getMsgId();
    }

    public void setMsgId(String msgId) {
        super.setMsgId(msgId);
    }

    public String getContent() {
        return super.getContent();
    }

    public void setContent(String content) {
        super.setContent(content);
    }

}
  • ImageMessage
package com.yd.wechat.message.normal;

import com.yd.wechat.message.common.Message;
import com.yd.wechat.message.common.MessageBody;

/***
 * 图片消息
 *
 * @param ToUserName 开发者微信号
 * @param FromUserName 发送方帐号(一个OpenID)
 * @param CreateTime 消息创建时间 (整型)
 * @param MsgType image
 * @param PicUrl 图片链接
 * @param MediaId 图片消息媒体id,可以调用多媒体文件下载接口拉取数据。
 * @param MsgId 消息id,64位整型
 *
 */
public class ImageMessage extends Message {

//  protected String PicUrl;
//  protected String MediaId;
//  protected String MsgId;

    public ImageMessage(MessageBody messageBody) {
        super(messageBody);
    }

    public String getPicUrl() {
        return super.getPicUrl();
    }

    public void setPicUrl(String picUrl) {
        super.setPicUrl(picUrl);
    }

    public String getMediaId() {
        return super.getMediaId();
    }

    public void setMediaId(String mediaId) {
        super.setMediaId(mediaId);
    }

    public String getMsgId() {
        return super.getMsgId();
    }

    public void setMsgId(String msgId) {
        super.setMsgId(msgId);
    }

}
  • VoiceMessage
package com.yd.wechat.message.normal;

import com.yd.wechat.message.common.Message;
import com.yd.wechat.message.common.MessageBody;

/***
 * 语音消息
 *
 * @param ToUserName 开发者微信号
 * @param FromUserName 发送方帐号(一个OpenID)
 * @param CreateTime 消息创建时间 (整型)
 * @param MsgType 语音为voice
 * @param MediaId 语音消息媒体id,可以调用多媒体文件下载接口拉取数据。
 * @param Format 语音格式,如amr,speex等
 * @param MsgID 消息id,64位整型
 */
public class VoiceMessage extends Message {

    //  protected String MediaId;
    //  protected String Format;
    //  protected String MsgId;

    public VoiceMessage(MessageBody messageBody) {
        super(messageBody);
    }

    public String getMediaId() {
        return super.getMediaId();
    }

    public void setMediaId(String mediaId) {
        super.setMediaId(mediaId);
    }

    public String getFormat() {
        return super.getFormat();
    }

    public void setFormat(String format) {
        super.setFormat(format);
    }

    public String getMsgId() {
        return super.getMsgId();
    }

    public void setMsgId(String msgId) {
        super.setMsgId(msgId);
    }

}
  • VideoMessage
package com.yd.wechat.message.normal;

import com.yd.wechat.message.common.Message;
import com.yd.wechat.message.common.MessageBody;

/**
 * 视频消息
 *
 * @param ToUserName 开发者微信号
 * @param FromUserName 发送方帐号(一个OpenID)
 * @param CreateTime 消息创建时间 (整型)
 * @param MsgType 视频为video
 * @param MediaId 视频消息媒体id,可以调用多媒体文件下载接口拉取数据。
 * @param ThumbMediaId 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
 * @param MsgId 消息id,64位整型
 *
 */
public class VideoMessage extends Message {

//  protected String MediaId;
//  protected String ThumbMediaId;
//  protected String MsgId;

    public VideoMessage(MessageBody messageBody) {
        super(messageBody);
    }

    public String getMediaId() {
        return super.getMediaId();
    }

    public void setMediaId(String mediaId) {
        super.setMediaId ( mediaId);
    }

    public String getThumbMediaId() {
        return super.getThumbMediaId();
    }

    public void setThumbMediaId(String thumbMediaId) {
        super.setThumbMediaId ( thumbMediaId);
    }

    public String getMsgId() {
        return super.getMsgId();
    }

    public void setMsgId(String msgId) {
        super.setMsgId ( msgId);
    }

}
  • ShortVideoMessage
package com.yd.wechat.message.normal;

import com.yd.wechat.message.common.Message;
import com.yd.wechat.message.common.MessageBody;

/**
 * 小视频消息
 *
 * @param ToUserName 开发者微信号
 * @param FromUserName 发送方帐号(一个OpenID)
 * @param CreateTime 消息创建时间 (整型)
 * @param MsgType 小视频为shortvideo
 * @param MediaId 视频消息媒体id,可以调用多媒体文件下载接口拉取数据。
 * @param ThumbMediaId 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
 * @param MsgId 消息id,64位整型
 */
public class ShortVideoMessage extends Message {

    //  protected String MediaId;
    //  protected String ThumbMediaId;
    //  protected String MsgId;

    public ShortVideoMessage(MessageBody messageBody) {
        super(messageBody);
    }

    public String getMediaId() {
        return super.getMediaId();
    }

    public void setMediaId(String mediaId) {
        super.setMediaId(mediaId);
    }

    public String getThumbMediaId() {
        return super.getThumbMediaId();
    }

    public void setThumbMediaId(String thumbMediaId) {
        super.setThumbMediaId(thumbMediaId);
    }

    public String getMsgId() {
        return super.getMsgId();
    }

    public void setMsgId(String msgId) {
        super.setMsgId(msgId);
    }

}
  • LinkMessage
package com.yd.wechat.message.normal;

import com.yd.wechat.message.common.Message;
import com.yd.wechat.message.common.MessageBody;

/**
 * 链接消息
 *
 * @param ToUserName 接收方微信号
 * @param FromUserName 发送方微信号,若为普通用户,则是一个OpenID
 * @param CreateTime 消息创建时间
 * @param MsgType 消息类型,link
 * @param Title 消息标题
 * @param Description 消息描述
 * @param Url 消息链接
 * @param MsgId 消息id,64位整型
 *
 */
public class LinkMessage extends Message {

    //  protected String Title;
    //  protected String Description;
    //  protected String Url;
    //  protected String MsgId;

    public LinkMessage(MessageBody messageBody) {
        super(messageBody);
    }

    public String getTitle() {
        return super.getTitle();
    }

    public void setTitle(String title) {
        super.setTitle(title);
    }

    public String getDescription() {
        return super.getDescription();
    }

    public void setDescription(String description) {
        super.setDescription(description);
    }

    public String getUrl() {
        return super.getUrl();
    }

    public void setUrl(String url) {
        super.setUrl(url);
    }

    public String getMsgId() {
        return super.getMsgId();
    }

    public void setMsgId(String msgId) {
        super.setMsgId(msgId);
    }

}
  • LocationMessage
package com.yd.wechat.message.normal;

import com.yd.wechat.message.common.Message;
import com.yd.wechat.message.common.MessageBody;

/***
 * 地理位置消息
 *
 * @param ToUserName 开发者微信号
 * @param FromUserName 发送方帐号(一个OpenID)
 * @param CreateTime 消息创建时间 (整型)
 * @param MsgType location
 * @param Location_X 地理位置维度
 * @param Location_Y 地理位置经度
 * @param Scale 地图缩放大小
 * @param Label 地理位置信息
 * @param MsgId 消息id,64位整型
 */
public class LocationMessage extends Message {

    //  protected String Location_X;
    //  protected String Location_Y;
    //  protected String Scale;
    //  protected String Label;
    //  protected String MsgId;

    public LocationMessage(MessageBody messageBody) {
        super(messageBody);
    }

    public String getLocation_X() {
        return super.getLocation_X();
    }

    public void setLocation_X(String location_X) {
        super.setLocation_X(location_X);
    }

    public String getLocation_Y() {
        return super.getLocation_Y();
    }

    public void setLocation_Y(String location_Y) {
        super.setLocation_Y(location_Y);
    }

    public String getScale() {
        return super.getScale();
    }

    public void setScale(String scale) {
        super.setScale(scale);
    }

    public String getLabel() {
        return super.getLabel();
    }

    public void setLabel(String label) {
        super.setLabel(label);
    }

    public String getMsgId() {
        return super.getMsgId();
    }

    public void setMsgId(String msgId) {
        super.setMsgId(msgId);
    }

}

总结

本节基本上完成了所有的类型的消息的接收,希望对大家有帮助。

由于个人时间有限,排版和对代码的修剪方面做得不是很好,希望大家多多包涵。下一节再见哦。

时间: 2024-10-05 10:45:42

一旦手把手教你开发微信公众平台2的相关文章

一旦手把手教你开发微信公众平台

一旦手把手教你开发微信公众平台 目录 一旦手把手教你开发微信公众平台 目录 1 初步认识微信公众平台 2 如何申请微信公众平台测试号 3 接口配置信息 4 环境搭建以及验证消息真实性 1: 初步认识微信公众平台 微信公众平台,简称weChat.曾命名为"官号平台"和"媒体平台",最终定位为"公众平台",无疑让我们看到一个微信对后续更大的期望.和新浪微博早期从明星战略着手不同,微信此时已经有了亿级的用户,挖掘自己用户的价值,为这个新的平台增加更优质

手把手教你建立微信公众平台

1.用电脑登录微信公众平台的官网:https://mp.weixin.qq.com/ 2.然后点击"注册"链接,注册一个帐号,点击后跳转到注册的页面: https://mp.weixin.qq.com/cgi-bin/readtemplate?t=register/step1_tmpl&lang=zh_CN 3.注册必须通过邮箱注册,而且,每个邮箱仅能申请一个帐号 4.注册后通过邮箱激活 5.然后,需要选择帐号类型!类型有订阅号.服务号.企业号三种.个人的话只能申请订阅号.区别

(转)手把手教你自制微信公众号流量监控系统

手把手教你自制微信公众号流量监控系统 一.首先是使用的工具: 基于搜狗微信搜索的微信公众号爬虫接口.Flask.ZUI框架. 第一个接口也是我开发的,欢迎star哈~ 二.获取数据 使用第一个接口获取公众号数据~ 可以看到,公众号的一般信息已经拿到手. 现在,将其集成到我们的网站上: (嗯,UI比较简单....) 三.监控 还是使用第一个接口监控数据: 这里做了一个嵌套排序,可以按照阅读量排序. 集成到网站上:四.具体的文章流量 继承到网站: 如上图所示,既可以监控微信号“NUAA_1952”的

[转]C#开发微信公众平台-就这么简单

本文转自:http://www.it165.net/pro/html/201403/11102.html 写在前面 服务号和订阅号 URL配置 创建菜单 查询.删除菜单 接受消息 发送消息(图文.菜单事件响应) 示例Demo下载 后记 最近公司在做微信开发,其实就是接口开发,网上找了很多资料,当然园友也写了很多教程,但都是理论说了一大堆,实用指导或代码很少.如果你自己仔细研究下,其实就那么点东西,C#实现起来也很简单,原本不想写这篇文章的,但是本人当时摸索走了很多弯路,这边总结下,希望初次接触微

[c#]asp.net开发微信公众平台(8)微信9大高级接口,自定义菜单

前7篇把最基础的消息接收和回复全做完了,  也把高级接口的入口和分拆处理写好了空方法,  此篇接着介绍微信的9大高级接口, 并着重讲解其中的自定义菜单. 微信9大接口为: 1.语音识别接口 2.客服接口 3.OAuth2.0 网页授权接口 4.生成带参数的二维码接口 5.获取用户地理位置接口 6.获取用户基本信息接口 7.获取关注者列表接口 8.用户分组接口 9.上传下载多媒体文件接口 具体介绍: 1. 语音识别 功能描述:通过语音识别接口,用户发送的语音,将同时给出语音识别出的文本内容. 实用

django开发微信公众平台遇到的问题记录

在pythonanywhere.com上使用django开发微信公众平台应用,结果用户发送的信息,微信服务器一次也没有成功转发到pythonanywhere上来,但是用接口测试工具调试却发现是正常的,而且修改URL配置时验证也是成功的,找了几天,终于发现原来是URL配置末尾少了个斜杠,因为在django的url配置中有斜杠. 原因是在后台配置URL的时候是手写的,而用测试工具测试的时候我是复制的地址. 总结: 如果发现微信服务器无法转发消息到自己的应用服务器上,检查配置,主要就是URL和TOKE

.net开发微信公众平台

一.说明:公众平台信息接口为开发者提供了一种新的消息处理方式,只有申请成为开发者后,你才能使用公众平台的开发功能,在这里你需要填写一个URL和一个Token,这两项信息也需要你拥有自己的服务器(外网服务器)资源,其中的Token可由开发者任意填写,URL即是接口配置信息的链接地址,在本文中我采用的是创建一个简易网站的方式,在其中的一个页面的后台程序中配置相关的接口信息,然后发布到外网服务器上,最后可以访问到这个页面的链接地址即是这里应该填写的URL. 二.接口配置过程: 1.网址接入-校验签名:

Jfinal开发微信公众平台

http://blog.csdn.net/lyq8479/article/details/8937622 方法就是柳峰老师发的教程,jfinal的区别就是核心servlet的处理可以用拦截器结合controller实现. 1.定义一个验证请求的拦截器 public class CoreFilterInterceptor implements Interceptor { // 验证请求来源拦截器 public void intercept(ActionInvocation ai) { Contro

Delphi XE7 用indy开发微信公众平台所有功能,可刷阅读,可刷赞,可加推广(除微支付)

http://www.cnblogs.com/devinlee/p/4565933.html Delphi XE7 用indy开发微信公众平台所有功能,可刷阅读,可刷赞,可加推广(除微支付) 关注作者的微信公众平台,测试效果 包含微信公众平台的所有功能(除微支付) 示例代码:(如需要全部代码,请加作者微信:Leedege) 复制代码 function UpNews(Num: Integer; AccessToken: String): String; var J: TJSONObject; N: