美文网首页微信小程序开发
微信订阅号消息API XML对象封装

微信订阅号消息API XML对象封装

作者: 西5d | 来源:发表于2020-01-21 14:53 被阅读0次

    前言

    这篇文章介绍微信订阅号消息接口中,XML对象的封装和解析。希望能给大家带来帮助,微信开发这块也不是很熟悉,只限跑通简单示例,懂行大佬轻拍。下面会详细介绍包括哪些内容。

    介绍

    对象主要包括两类,普通消息和推送消息。以及一个通用的转换工具类,类似fastjson的工具类。 为简单起见这里把语音,文本,图片等各自特有的字段都整合到一个对象里,方便使用,缺点是字段显得多些。要补充的是,代码只限跑通例子,对于性能,规范等方面没有做过多的考虑。其中推送消息类有问题,无法使用,普通消息解析是正常的,可以用以下对应的单测例子debug校验。

    代码

    接口对象

    //消息对象类
    @Data //lombok 注解
    @XmlAccessorType(XmlAccessType.FIELD) //必须
    @XmlRootElement(name = "xml")
    public class WxMsg {
        @XmlElement(name = "ToUserName")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String toUserName; //接收方微信号
    
        @XmlElement(name = "FromUserName")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String fromUserName;//发送方微信号,若为普通用户,则是一个OpenID
    
        @XmlElement(name = "CreateTime")
        private Long createTime;//消息创建时间 (整型)
    
        @XmlElement(name = "MsgType")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String msgType;//video voice text image location link
    
        @XmlElement(name = "PicUrl")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String picUrl; //   图片链接(由系统生成)
    
        @XmlElement(name = "Content")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String content; //文本消息内容
    
        @XmlElement(name = "MediaId")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String mediaId;//视频消息媒体id,可以调用获取临时素材接口拉取数据。
    
        @XmlElement(name = "Format")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String format; //语音格式:amr speex等
    
        @XmlElement(name = "Recognition")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String recognition; //  语音识别结果,UTF8编码
    
        @XmlElement(name = "ThumbMediaId")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String thumbMediaId;//视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
    
        @XmlElement(name = "Title")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String title; //链接消息标题
    
        @XmlElement(name = "Description")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String description; //链接消息描述
    
        @XmlElement(name = "Url")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String url; //链接消息link
    
        @XmlElement(name = "Location_X")
        private String locationX; //地理位置纬度
    
        @XmlElement(name = "Location_Y")
        private String locationY; //地理位置经度
    
        @XmlElement(name = "Scale")
        private Integer scale; //地理精度
    
        @XmlElement(name = "Label")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String label; //地理位置详情
    
        @XmlElement(name = "ArticleCount")
        private Integer articleCount; //图文消息文章数量
    
        @XmlElement(name = "MsgId")
        private Long msgId; //消息id,64位整型
    
        /**
         * 附加类型
         **/
        @XmlElement(name = "Music")
        private WxMusic music;
    
        @XmlElement(name = "Voice")
        private WxVoice wxVoice;
    
        @XmlElement(name = "Video")
        private WxVideo wxVideo;
    
        @XmlElement(name = "Image")
        private WxImage wxImage;
    
        @XmlElement(name = "Articles")
        private WxNews articles;
    
    
        @Getter
        @AllArgsConstructor
        public enum MsgType {
            UnKnow(-1, "unknow", "未知类型"),
            Text(1, "text", "文本"),
            Voice(2, "voice", "语音"),
            Image(3, "image", "图像"),
            Location(4, "location", "位置"),
            Link(5, "link", "链接"),
            Event(6, "event", "推送"),
            Video(7, "video", "视频"),
            Music(8, "music", "音乐"),
            News(9, "news", "图文");
    
            private int code;
            private String key;
            private String desc;
    
            public static MsgType fromKey(String key) {
                return Arrays.stream(MsgType.values()).filter(e -> e.key.equals(key)).findFirst().orElse(MsgType.UnKnow);
            }
        }
    }
    
    
    //推送消息类
    @EqualsAndHashCode(callSuper = true)
    @Data
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlRootElement(name = "xml")
    public class WxEventMsg extends WxMsg {
    
        @XmlElement(name = "Event")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String event; //事件类型,subscribe(订阅)、unsubscribe(取消订阅)    事件类型,LOCATION 菜单 CLICK 跳转 VIEW
    
        @XmlElement(name = "EventKey")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String eventKey; //未关注:事件KEY值,qrscene_为前缀,后面为二维码的参数值 , 已关注:事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id 菜单:事件KEY值,与自定义菜单接口中KEY值对应 ; 跳转: 配置的url
    
        @XmlElement(name = "Ticket")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String ticket; //二维码的ticket,可用来换取二维码图片
    
        @XmlElement(name = "Latitude")
        private String latitude; //地理位置纬度
    
        @XmlElement(name = "Longitude")
        private String longitude; //地理位置经度
    
        @XmlElement(name = "Precision")
        private String precision; //地理位置精度 浮点
    
        @XmlElement(name = "ScanCodeInfo")
        private WxScan scanCodeInfo;
    
        @XmlElement(name = "MenuId")
        private String menuId; //菜单ID,如果是个性化菜单,则可以通过这个字段,知道是哪个规则的菜单被点击了
    
    
        @Getter
        @AllArgsConstructor
        public enum EventType {
            UnKnow(-1, "unkown", "未知类型"),
            Subscribe(1, "subscribe", "加入订阅"),
            Unsubscribe(2, "unsubscribe", "取消订阅"),
            Location(3, "LOCATION", "位置"),
            MenuClick(4, "CLICK", "菜单点击"),
            ViewClick(5, "VIEW", "链接点击"),
            ScanPush(6, "scancode_push", "扫码"),
            ScanWaitMsg(7, "scancode_waitmsg", "扫码推事件且弹出“消息接收中”提示框的事件推送"),
            PicSysPhoto(8, "pic_sysphoto", "系统拍照"),
            ViewMiniProgram(9, "view_miniprogram", "点击菜单跳转小程序的事件推送"),
            PicWeixin(10, "pic_weixin", "弹出微信相册发图器的事件推送"),
            ;
    
            private int code;
            private String key;
            private String desc;
        }
    }
    
    //几个扩展消息
    
    @Data
    @XmlAccessorType(XmlAccessType.FIELD)
    public class WxImage {
    
        @XmlElement(name = "MediaId")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String mediaId;
    
    }
    
    @Data
    @XmlAccessorType(XmlAccessType.FIELD)
    public class WxMusic {
    
        @XmlElement(name = "Title")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String title; //音乐标题
    
        @XmlElement(name = "Description")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String description; //音乐描述
    
        @XmlElement(name = "MusicUrl")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String musicUrl; //音乐链接
    
        @XmlElement(name = "HQMusicUrl")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String hqMusicUrl; //高质量音乐链接,WIFI环境优先使用该链接播放音乐
    
        @XmlElement(name = "ThumbMediaId")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String thumbMediaId; //缩略图的媒体id,通过素材管理中的接口上传多媒体文件,得到的id
    }
    
    @Data
    @XmlAccessorType(XmlAccessType.FIELD)
    public class WxNews {
    
        @XmlElement(name = "item")
        List<Item> item;
    
    
        @Data
        @XmlAccessorType(XmlAccessType.FIELD)
        public static class Item {
            @XmlElement(name = "Title")
            @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
            private String title; //图文消息标题
    
            @XmlElement(name = "Description")
            @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
            private String description; //图文消息描述
    
            @XmlElement(name = "PicUrl")
            @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
            private String picUrl; //图片链接,支持JPG、PNG格式,较好的效果为大图360*200,小图200*200
    
            @XmlElement(name = "Url")
            @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
            private String url; //点击图文消息跳转链接
        }
    }
    
    @Data
    public class WxScan {
        @XmlElement(name = "ScanType")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String scanType; //扫描结果,即二维码对应的字符串信息
    
        @XmlElement(name = "ScanResult")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String scanResult; //扫描结果,即二维码对应的字符串信息
    }
    
    @Data
    @XmlAccessorType(XmlAccessType.FIELD)
    public class WxVideo {
        @XmlElement(name = "MediaId")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String mediaId; //通过素材管理中的接口上传多媒体文件,得到的id
    
        @XmlElement(name = "Title")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String title; //视频消息的标题
    
        @XmlElement(name = "Description")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String description; //视频消息的描述
    }
    
    @Data
    @XmlAccessorType(XmlAccessType.FIELD)
    public class WxVoice {
        @XmlElement(name = "MediaId")
        @XmlJavaTypeAdapter(XmlUtil.CDATAAdapter.class)
        private String mediaId;
    }
    
    

    封装XML解析类

    
    public class XmlUtil {
    
        public static <T> T parseXml(String input, Class<T> tClass) {
            try {
                JAXBContext jaxbContext = JAXBContext.newInstance(tClass);
                Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
                StringReader reader = new StringReader(input);
                T obj = (T) unmarshaller.unmarshal(reader);
                return obj;
            } catch (Exception ignore) {
                return null;
            }
        }
    
        //核心都是使用的jdk自带 rt.jar
        public static <T> String toXml(T obj) {
            try {
                JAXBContext jaxbContext = JAXBContext.newInstance(obj.getClass());
                Marshaller malshaller = jaxbContext.createMarshaller();
                StringWriter writer = new StringWriter();
                malshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
                malshaller.setProperty("com.sun.xml.internal.bind.characterEscapeHandler",
                        (CharacterEscapeHandler) (ch, start, length, isAttVal, writer1) -> writer1.write(ch, start, length)); //不转义内容 如amp;, 可以取消这个参数试试
                malshaller.setProperty("com.sun.xml.internal.bind.xmlDeclaration", false);//去除 <?xml version="1.0" encoding="UTF-8" ?> 头
                malshaller.marshal(obj, writer);
                return writer.toString();
            } catch (Exception ignore) {
                return null;
            }
        }
    
        //CDATA 格式内容的处理
        public static class CDATAAdapter extends XmlAdapter<String, String> {
    
            @Override
            public String marshal(String v) throws Exception {
                return "<![CDATA[" + v + "]]>";
            }
    
            @Override
            public String unmarshal(String v) throws Exception {
                return v;
            }
        }
    }
    
    

    测试例子

        @Test
        public void xmlTest() {
            String data = "<xml>\n"
                    + "  <ToUserName><![CDATA[toUser]]></ToUserName>\n"
                    + "  <FromUserName><![CDATA[fromUser]]></FromUserName>\n"
                    + "  <CreateTime>1348831860</CreateTime>\n"
                    + "  <MsgType><![CDATA[image]]></MsgType>\n"
                    + "  <PicUrl><![CDATA[this is a url]]></PicUrl>\n"
                    + "  <MediaId><![CDATA[media_id]]></MediaId>\n"
                    + "  <MsgId>1234567890123456</MsgId>\n"
                    + "</xml>\n"
                    + "\n";
            WxMsg msg = XmlUtil.parseXml(data, WxMsg.class);
            System.out.println(msg);
        }
    
        @Test
        public void xmlStringTest() {
            WxMsg msg = new WxMsg();
            msg.setCreateTime(222244L);
            msg.setPicUrl("hsdgfsdgsdgsdg");
            System.out.println(XmlUtil.toXml(msg));
        }
    
        @Test
        public void wxNewsTest() {
            String news = "<xml>\n"
                    + "    <ToUserName><![CDATA[toUser]]></ToUserName>\n"
                    + "    <FromUserName><![CDATA[fromUser]]></FromUserName>\n"
                    + "    <CreateTime>12345678</CreateTime>\n"
                    + "    <MsgType><![CDATA[news]]></MsgType>\n"
                    + "    <ArticleCount>1</ArticleCount>\n"
                    + "    <Articles>\n"
                    + "        <item>\n"
                    + "            <Title><![CDATA[sdgsdngaosdng]]></Title>\n"
                    + "            <Description><![CDATA[fsdfsdgsdgsdg]]></Description>\n"
                    + "            <PicUrl><![CDATA[sdnongsd]]></PicUrl>\n"
                    + "            <Url><![CDATA[sdnobvnsdiong]]></Url>\n"
                    + "        </item>\n"
                    + "        <item>\n"
                    + "            <Title><![CDATA[sdgsdngaosdng]]></Title>\n"
                    + "            <Description><![CDATA[fsdfsdgsdgsdg]]></Description>\n"
                    + "            <PicUrl><![CDATA[sdnongsd]]></PicUrl>\n"
                    + "            <Url><![CDATA[sdnobvnsdiong]]></Url>\n"
                    + "        </item>\n"
                    + "    </Articles>\n"
                    + "</xml>";
            WxMsg msg = XmlUtil.parseXml(news, WxMsg.class);
            System.out.println(msg);
    
            WxNews.Item news1 = new WxNews.Item();
            WxNews wxNews = new WxNews();
            news1.setDescription("fsdfsdgsdgsdg");
            news1.setTitle("sdgsdngaosdng");
            news1.setUrl("sdnobvnsdiong");
            news1.setPicUrl("sdnongsd");
            msg.setArticles(wxNews);
            wxNews.setItem(Lists.newArrayList(news1,news1));
            System.out.println(XmlUtil.toXml(msg));
        }
    

    结语

    至此结束。再次补充下,代码只限跑通例子,对于性能,规范等方面没有做过多的考虑,有类似需求的可以加以修改优化;如果使用maven打包,报找不到rt.jar问题,按如下补充pom.xml配置:

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                        <compilerArgs>
                            <arg>-XDignore.symbol.file</arg>
                        </compilerArgs>
                        <fork>true</fork>
                    </configuration>
                </plugin>
    

    谢谢。

    相关文章

      网友评论

        本文标题:微信订阅号消息API XML对象封装

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