微信小程序开发

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

2020-01-21  本文已影响0人  西5d

前言

这篇文章介绍微信订阅号消息接口中,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>

谢谢。

上一篇下一篇

猜你喜欢

热点阅读