疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java接入微信公众号(3):输入消息解析模块设计


 

 本次主要是解决微信平台发送信息到我们自身的服务器以后,我们需要把信息转换为Java对象,方便后面处理。本文主要描述消息转换接口、消息体系的介绍。下次将介绍具体如何分发消息。
整体流程:定义消息类 -> 编写转换器 -> 在消息分发程序中,转换消息 -> 转换后的消息放入Kafka队列

 wechat-消息对象、消息转换器、消息分发程序代码.zip (183.83 KB, 下载次数: 0) 

先简单说明一下抽象的接口和类。
 

Message类是整个消息的顶级父类,不仅仅是输入的消息,输出的消息也继承此类。

  • @XmlRootElement(name = "xml")
  • @XmlAccessorType(value = XmlAccessType.FIELD)
  • public abstract class Message {
  •  
  •     @XmlElement(name = "FromUserName")
  •     private String from;
  •     @XmlElement(name = "ToUserName")
  •     private String to;
  •     @XmlElement(name = "CreateTime")
  •     private Long createTime;
  •     @XmlElement(name = "MsgType")
  •     private String type;
  • }



InMessage输入消息在此基础上稍微有一些扩展,多了MsgId

  • public abstract class InMessage extends Message {
  •  
  •     @XmlElement(name = "MsgId")
  •     private String msgId;
  • }



OutMessage输出消息暂时不考虑,目前只是预留


MessageConverter则定义了消息转换的顶层接口

  • /**
  • *
  • * @author 罗文强<luo_wenqiang@qq.com>
  • * @param 输入源
  • * @param 被转换出来的目标
  • */
  • interface MessageConverter<SRC, TARGET> {
  •  
  •     /**
  •      * 执行信息的转换过程,把SRC转换为TARGET
  •      *
  •      * @param src
  •      * @return
  •      */
  •     TARGET convert(SRC src);
  • }



InMessageConverter实现了通用的输入消息转换机制,但是也增加了一个抽象方法用于判断消息类型

  • /**
  • * 接收到的消息转换器
  • *
  • * @author 罗文强<luo_wenqiang@qq.com>
  • * @param 传入的是String或者byte[],为XML格式,返回的是InMessage(子类)对象
  • */
  • public interface InMessageConverter<TARGET extends InMessage>
  •         extends MessageConverter<String, TARGET> {
  •  
  •     /**
  •      * 判断转换器能否支持对应类型的消息转换
  •      *
  •      * @param type 微信传入的消息类型
  •      * @return
  •      */
  •     boolean accept(String type);
  •  
  •     @Override
  •     default TARGET convert(String src) {
  •         // 获取当前实例的类泛型化的接口
  •         Type[] types = this.getClass().getGenericInterfaces();
  •         // 输入的消息只有一个泛型接口,直接取出来使用
  •         Type type = types[0];
  •         // 获取到的类型,是泛型化类型
  •         ParameterizedType parameterizedType = (ParameterizedType) type;
  •         // 泛型化类型可以获取实际类型参数
  •         Type[] actualTypes = parameterizedType.getActualTypeArguments();
  •         // 同样,泛型化参数的第一个,则是消息的实际类型
  •         @SuppressWarnings("unchecked")
  •         Class<TARGET> actualType = (Class<TARGET>) actualTypes[0];
  •  
  •         // 通过JAXB把得到的XML字符串转换为输入消息对象
  •         StringReader reader = new StringReader(src);
  •         return JAXB.unmarshal(reader, actualType);
  •     }
  • }



具体的消息转换实现非常简单,只需要继承InMessage,并且实现InMessageConverter接口即可,下面以文本消息为例,其他的消息转换,请下载完整源代码来阅读。

  • public class InMessageText extends InMessage {
  •  
  •     /**
  •      * 文本消息内容
  •      */
  •     @XmlElement(name = "Content")
  •     private String content;
  • }
  •  

 

  • public class InMessageTextConverter implements InMessageConverter<InMessageText> {
  •  
  •     @Override
  •     public boolean accept(String type) {
  •         return "text".equals(type);
  •     }
  • }



把消息处理器的实现类名,记录到特殊文件里面,以便被ServiceLoader加载进来使用
 


所有的消息转换器,都要加入到【消息分发程序】模块中,消息分发程序的具体设计,参见http://www.crazyit.org/thread-12458-1-1.html。在消息分发程序模块中,需要查找合适的转换器,对消息进行转换,并存入wechat-in-message队列中。

  • /**
  • *
  • * @author 罗文强<luo_wenqiang@qq.com>
  • */
  • @Service
  • public class MessageDispatcher {
  •  
  •     private static final Logger LOG = LoggerFactory.getLogger