welcome to xlongwei.com

欢迎大家一起学习、交流、分享


QQ:9167702333 邮箱:admin@xlongwei.com

微信公众号消息封装


分类 Java   关键字 分享   标签 java   algorithm   发布 hongwei  1464155573829
注意 转载须保留原文链接,译文链接,作者译者等信息。  
微信公众号消息是 xml 数据,因此 xml 的解析和生成是难点,得益于XMLObject对xml的灵活处理,消息类Message的封装变得较为容易,详见下文。

抽象类Message封装消息基础字段
public static abstract class Message {
private String ToUserName; // 开发者微信号
private String FromUserName; // 发送方帐号(一个OpenID)
private long CreateTime; // 消息创建时间 (整型)
protected String MsgType; // 消息类型(text/image/location/link)
private long MsgId;// 消息id,64位整型

与xml格式互转是难点,这里借鉴了bean的概念,直接反射读取pojo字段,使用XMLObject生成xml数据
public String toXML() {
XMLObject xml = new XMLObject("xml");
try {
Field[] fields = Message.getFields(this.getClass());
boolean isEvent = Type.event.equals(getMsgType());
for(Field field : fields) {
if(isEvent && "MsgId".equals(field.getName())) continue; //event没有MsgId字段
Object value = field.get(this);
xml.add(field.getName(), value==null ? "" : XMLObject.CDATA(value.toString()));
}
}catch(Exception e) {
logger.info(e.getMessage());
}
return xml.toString();
}

解析xml时需要知道消息的具体类型,从而找到特定的消息实例Class并实例化,然后从xml获取值并赋值给相关字段
public static Message fromXML(String xml) {
XMLObject obj = XMLObject.fromXML(xml);
String MsgType = obj.get("MsgType");
Class<? extends Message> clazz = classCache.get(MsgType);
boolean isEvent = false; //事件继承自消息,统一处理
if(clazz == null && Type.event.equals(MsgType)){
isEvent = true;
String event = obj.get("Event");
if(Event.Type.subscribe.equals(event)) {
String ticket = obj.get("Ticket");
if(!StringUtil.isBlank(ticket)) {
clazz = classCache.get(MsgType+"."+Event.Type.SCAN);
}
}
if(clazz == null) clazz = classCache.get(MsgType+"."+event);
}
if(clazz != null) {
try {
Message msg = clazz.newInstance();
Field[] fields = Message.getFields(msg.getClass());
for(Field field : fields) {
if(isEvent && "MsgId".equals(field.getName())) continue; //event没有MsgId字段
String value = obj.get(field.getName());
if(value != null) {
Object convert = ConvertUtils.convert(value, field.getType());
field.set(msg, convert);
}
}
return msg;
} catch (Exception e) {
logger.info(e.getMessage());
}
}
return null;
}

消息实例,最常用的就是文本消息,TextMessage

public static class TextMessage extends Message {
private String Content; // 消息内容
public TextMessage() { this.MsgType = Type.text; } //消息实例必须有MsgType值,解析xml时也是根据此值查找合适的Class对象
}

事件除了没有MsgId,其他基础字段与消息相同,因此事件Event可以考虑继承消息Message
public static abstract class Event extends Message {
protected String Event;//事件类型,subscribe(订阅)、unsubscribe(取消订阅)
public Event() { this.MsgType = Message.Type.event; } //类似于消息实例,但它是抽象的

事件实例,最常用的就是关注事件SubscribeEvent和点击事件ClickEvent,
public static class SubscribeEvent extends Event {
public SubscribeEvent() { this.Event = Type.subscribe; } //关注和取消关注,事件类型不同
}
public static class ClickEvent extends Event {
private String EventKey;//事件KEY值,与自定义菜单接口中KEY值对应
public ClickEvent() { this.Event = Type.CLICK; } //事件MsgType=event,事件类型用于区分各种事件
}

事件的解析与消息一致,都是将Class和Filed[]缓存起来,然后事件实例与xml以bean的方式互转。