前言
這篇文章介紹微信訂閱號消息接口中,XML對象的封裝和解析。希望能給大家帶來幫助,微信開發這塊也不是很熟悉,只限跑通簡單示例,懂行大佬輕拍。下面會詳細介紹包括哪些內容。
介紹
對象主要包括兩類,普通消息和推送消息。以及一個通用的轉換工具類,類似fastjson的工具類。 為簡單起見這裡把語音,文本,圖片等各自特有的字段都整合到一個對象裡,方便使用,缺點是字段顯得多些。要補充的是,代碼只限跑通例子,對於性能,規範等方面沒有做過多的考慮。其中推送消息類有問題,無法使用,普通消息解析是正常的,可以用以下對應的單測例子debug校驗。
代碼
接口對象
<code>//消息對象類
@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);
}
}
}
/<code>
<code>//推送消息類
@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;
}
}
/<code>
<code>//幾個擴展消息
@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;
}
/<item>/<code>
![訂閱號消息API XML對象封裝](http://p2.ttnews.xyz/loading.gif)
封裝XML解析類
<code>
public class XmlUtil {
public staticT parseXml(String input, Class /<code>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 staticString 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);//去除 頭
malshaller.marshal(obj, writer);
return writer.toString();
} catch (Exception ignore) {
return null;
}
}
//CDATA 格式內容的處理
public static class CDATAAdapter extends XmlAdapter<string> {
@Override
public String marshal(String v) throws Exception {
return "";
}
@Override
public String unmarshal(String v) throws Exception {
return v;
}
}
}
/<string>
測試例子
<code> @Test
public void xmlTest() {
String data = "\\n" \\n"
+ " <tousername>\\n"
+ " <fromusername>\\n"
+ " <createtime>1348831860/<createtime>\\n"
+ " <msgtype>\\n"
+ " <picurl>\\n"
+ " <mediaid>\\n"
+ " <msgid>1234567890123456/<msgid>\\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 = "\\n" ";
+ " <tousername>\\n"
+ " <fromusername>\\n"
+ " <createtime>12345678/<createtime>\\n"
+ " <msgtype>\\n"
+ " <articlecount>1/<articlecount>\\n"
+ " <articles>\\n"
+ " <item>\\n"
+ " <title>\\n"
+ " <description>\\n"
+ " <picurl>\\n"
+ "\\n"
+ " /<item>\\n"
+ " <item>\\n"
+ " <title>\\n"
+ " <description>\\n"
+ " <picurl>\\n"
+ "\\n"
+ " /<item>\\n"
+ " /<articles>\\n"
+ "
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));
}
/<code>
結語
至此結束。再次補充下,代碼只限跑通例子,對於性能,規範等方面沒有做過多的考慮,有類似需求的可以加以修改優化;如果使用maven打包,報找不到rt.jar問題,按如下補充pom.xml配置:
<code> <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>
-XDignore.symbol.file
/<compilerargs>
<fork>true/<fork>
/<configuration>
/<plugin>
/<code>
謝謝。
閱讀更多 舉大栗子 的文章