美文网首页
【干货】订阅号开发[2]--消息的封装

【干货】订阅号开发[2]--消息的封装

作者: 5d44bc28b93d | 来源:发表于2018-11-20 11:48 被阅读12次

订阅号消息事件封装

订阅号.png

消息事件的封装其实是比较细节的。后面会提到一些细节。

分析微信消息

消息类型分析

  1. image 图片消息
<xml> 
    <ToUserName>< ![CDATA[toUser] ]></ToUserName> 
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>1348831860</CreateTime> 
    <MsgType>< ![CDATA[image] ]></MsgType> 
    <PicUrl>< ![CDATA[this is a url] ]></PicUrl> 
    <MediaId>< ![CDATA[media_id] ]></MediaId> 
    <MsgId>1234567890123456</MsgId> 
</xml>

  1. text 文本消息
<xml>  
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>  
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>1348831860</CreateTime>  
    <MsgType>< ![CDATA[text] ]></MsgType>  
    <Content>< ![CDATA[this is a test] ]></Content>  
    <MsgId>1234567890123456</MsgId>  
</xml>
  1. voice 语音消息
<xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser]></FromUserName>
    <CreateTime>1357290913</CreateTime>
    <MsgType>< ![CDATA[voice] ]></MsgType>
    <MediaId>< ![CDATA[media_id] ]></MediaId>
    <Format>< ![CDATA[Format] ]></Format>
    <MsgId>1234567890123456</MsgId>
</xml>
  1. video视频消息
<xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>1357290913</CreateTime>
    <MsgType>< ![CDATA[video] ]></MsgType>
    <MediaId>< ![CDATA[media_id] ]></MediaId>
    <ThumbMediaId>< ![CDATA[thumb_media_id] ]></ThumbMediaId>
    <MsgId>1234567890123456</MsgId>
</xml>
  1. shortvideo 小视频信息
<xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>1357290913</CreateTime>
    <MsgType>< ![CDATA[shortvideo] ]></MsgType>
    <MediaId>< ![CDATA[media_id] ]></MediaId>
    <ThumbMediaId>< ![CDATA[thumb_media_id] ]></ThumbMediaId>
    <MsgId>1234567890123456</MsgId>
</xml>
  1. location 地理位置信息
<xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>1351776360</CreateTime>
    <MsgType>< ![CDATA[location] ]></MsgType>
    <Location_X>23.134521</Location_X>
    <Location_Y>113.358803</Location_Y>
    <Scale>20</Scale>
    <Label>< ![CDATA[位置信息] ]></Label>
    <MsgId>1234567890123456</MsgId>
</xml>
  1. link 链接信息
<xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>1351776360</CreateTime>
    <MsgType>< ![CDATA[link] ]></MsgType>
    <Title>< ![CDATA[公众平台官网链接] ]></Title>
    <Description>< ![CDATA[公众平台官网链接] ]></Description>
    <Url>< ![CDATA[url] ]></Url>
    <MsgId>1234567890123456</MsgId>
</xml>
  1. event(下章介绍)

以上具体字段含义请参考微信api官网文档

封装实现

  1. 公共属性提取
  2. 利于转化为微信能识别的xml格式
公共属性BaseMessage
public class BaseMessage {
    @XStreamAlias("ToUserName")
    private String toUserName;
    @XStreamAlias("FromUserName")
    private String fromUserName;
    @XStreamAlias("CreateTime")
    private long createTime;
    @XStreamAlias("MsgId")
    private long msgId;

    public enum MsgType {
        image, text, voice, video, shortvideo, location, link, event
    }
}
text文本消息
@XStreamAlias("xml")
public class TextMessage extends BaseMessage {
    @XStreamAlias("Content")
    private String content;
    @XStreamAlias("MsgType")
    private final MsgType msgType = MsgType.text;
    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public MsgType getMsgType() {
        return msgType;
    }

}
image图片消息
@XStreamAlias("xml")
public class ImageMessage extends BaseMessage{
    @XStreamAlias("PicUrl")
   private String picUrl;
    @XStreamAlias("MsgType")
   private final MsgType msgType = MsgType.image;
    @XStreamAlias("MediaId")
    private String mediaId;
}
video视频消息
@XStreamAlias("xml")
public class VideoMessage extends BaseMessage {
    @XStreamAlias("MediaId")
    private String mediaId;
    @XStreamAlias("MsgType")
    private final MsgType msgType = MsgType.video;
    @XStreamAlias("ThumbMediaId")
    private String thumbMediaId;
}
shortvideo短视频消息
@XStreamAlias("xml")
public class ShortVideoMessage extends BaseMessage {
    @XStreamAlias("MediaId")
    private String mediaId;
    @XStreamAlias("MsgType")
    private final MsgType msgType = MsgType.shortvideo;
    @XStreamAlias("ThumbMediaId")
    private String thumbMediaId;
}
link连接消息
@XStreamAlias("xml")
public class LinkMessage extends BaseMessage {
    @XStreamAlias("Title")
    private String title;
    @XStreamAlias("Description")
    private String description;
    @XStreamAlias("MsgType")
    private final MsgType msgType = MsgType.link;
    @XStreamAlias("Url")
    private String url;
}

Location 地理位置消息
@XStreamAlias("xml")
public class LocationMessage extends BaseMessage {
    @XStreamAlias("Location_X")
    private String location_X;
    @XStreamAlias("Location_Y")
    private String location_Y;
    @XStreamAlias("MsgType")
    private final MsgType msgType = MsgType.location;
    @XStreamAlias("Scale")
    private String scale;
    @XStreamAlias("Lable")
    private String label;
}
voice语音消息
@XStreamAlias("xml")
public class VoiceMessage extends BaseMessage{
    @XStreamAlias("MediaId")
    private String mediaId;
    @XStreamAlias("MsgType")
    private final MsgType msgType = MsgType.voice;
    @XStreamAlias("Format")
    private String format;
    @XStreamAlias("Recognition")
    private String recognition;
}

以上就是封装内容,@XStreamAlias很重要,这是一个xml解析成对象,对象转换成xml的工具包(xstream)提供的,详见pom文件。其中的@XStreamAlias("xml")就是转换成xml是作为节点的名字用的。

<xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>1351776360</CreateTime>
    <MsgType>< ![CDATA[link] ]></MsgType>
    <Title>< ![CDATA[公众平台官网链接] ]></Title>
    <Description>< ![CDATA[公众平台官网链接] ]></Description>
    <Url>< ![CDATA[url] ]></Url>
    <MsgId>1234567890123456</MsgId>
</xml>

这样就不用傻傻的把成员变量定义成首字母大写吧?

依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.11</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.51</version>
        </dependency>

        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>

        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.4.11.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.3</version>
        </dependency>
    </dependencies>

xstream 转换时如何变成微信想要的样子

MessageUtil封装
public class MessageUtil {
    /**
     * 将信息转换成符合微信服务器需要的xml字符串
     * @param message 消息实体(video,text,......等等所有的消息公用)
     * @param <T> 泛型可以传递任意的类型消息
     * @return
     */
    public static <T> String messageToXml(T message) {
        XStream xstream = getXstream();
        //xstream 处理注解如:@XStreamAlias("CreateTime")
        xstream.processAnnotations(message.getClass());
        return xstream.toXML(message);
    }

    /**
     *
     * @param xml xml文本消息转换成消息实体
     * @param cls 需要转换的消息类型
     * @param <V> 泛型 返回你传递的消息类型实体
     * @return
     */
    public static <V> V xmlToMessage(String xml, Class<V> cls) {
        XStream xstream = getXstream();
        xstream.processAnnotations(cls);
        return (V) xstream.fromXML(xml);
    }

    /**
     * 将xml字符串转换成Map
     * @param xml xml字符串
     * @return
     * @throws Exception
     */
    public static Map<String, String> parseXml(String xml) throws Exception {
        Map<String, String> map = new HashMap<>();
        SAXReader reader = new SAXReader();
        Document document = reader.read(new ByteArrayInputStream(xml.getBytes()));
        Element root = document.getRootElement();
        List<Element> elementList = root.elements();
        for (Element e : elementList)
            map.put(e.getName(), e.getText());
        return map;
    }

    /**
     * 解析request的请求内容
     * @param request
     * @return
     * @throws IOException
     */
    public static String requestToXml(HttpServletRequest request) throws IOException {
        InputStream inputStream = request.getInputStream();
        String result = new BufferedReader(new InputStreamReader(inputStream))
                .lines().collect(Collectors.joining(System.lineSeparator()));
        return result;
    }

    /**
     * 定制Xstream 对所有xml节点的转换都增加CDATA标记
     * @return
     */
    private static XStream getXstream() {
        return new XStream(new XppDriver() {
            public HierarchicalStreamWriter createWriter(Writer out) {
                return new PrettyPrintWriter(out) {
                    // 对所有xml节点的转换都增加CDATA标记
                    boolean cdata = true;

                    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);
                        }
                    }
                };
            }
        });
    }
}


测试验证

public class MessageUtilTest {
    @Test
    public void beanToXml(){
        TextMessage textMessage = new TextMessage();
        textMessage.setFromUserName("ppb");
        textMessage.setToUserName("aaa");
        textMessage.setContent("笔芯");
        textMessage.setCreateTime(new Date().getTime());
        String responseMessage = MessageUtil.messageToXml(textMessage);
        assertNotNull(responseMessage);
        TextMessage textMessage1 = MessageUtil.xmlToMessage(responseMessage,TextMessage.class);
        assertNotNull(textMessage1);
    }
}

总结

消息的封装以及处理都差不多了。感觉有帮助就点个赞

相关文章

网友评论

      本文标题:【干货】订阅号开发[2]--消息的封装

      本文链接:https://www.haomeiwen.com/subject/aqbtqqtx.html