调整MessageKey和MessageMatcher

This commit is contained in:
jinyu 2015-06-10 00:04:06 +08:00
parent 3696b813dd
commit 0b1cca67a4
11 changed files with 309 additions and 187 deletions

View File

@ -0,0 +1,167 @@
package com.foxinmy.weixin4j.dispatcher;
import java.util.HashMap;
import java.util.Map;
import com.foxinmy.weixin4j.message.ImageMessage;
import com.foxinmy.weixin4j.message.LinkMessage;
import com.foxinmy.weixin4j.message.LocationMessage;
import com.foxinmy.weixin4j.message.TextMessage;
import com.foxinmy.weixin4j.message.VideoMessage;
import com.foxinmy.weixin4j.message.VoiceMessage;
import com.foxinmy.weixin4j.message.event.LocationEventMessage;
import com.foxinmy.weixin4j.message.event.MenuEventMessage;
import com.foxinmy.weixin4j.message.event.MenuLocationEventMessage;
import com.foxinmy.weixin4j.message.event.MenuPhotoEventMessage;
import com.foxinmy.weixin4j.message.event.MenuScanEventMessage;
import com.foxinmy.weixin4j.mp.event.KfCloseEventMessage;
import com.foxinmy.weixin4j.mp.event.KfCreateEventMessage;
import com.foxinmy.weixin4j.mp.event.KfSwitchEventMessage;
import com.foxinmy.weixin4j.mp.event.MassEventMessage;
import com.foxinmy.weixin4j.mp.event.TemplatesendjobfinishMessage;
import com.foxinmy.weixin4j.qy.event.BatchjobresultMessage;
import com.foxinmy.weixin4j.qy.event.EnterAgentEventMessage;
import com.foxinmy.weixin4j.type.AccountType;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
public class DefaultMessageMatcher implements WeixinMessageMatcher {
private final Map<MessageKey, Class<?>> messageClassMap;
public DefaultMessageMatcher() {
messageClassMap = new HashMap<MessageKey, Class<?>>();
initMessageClass();
}
private void initMessageClass() {
// /////////////////////////////////////////////////
/******************** 普通消息 ********************/
// /////////////////////////////////////////////////
initGeneralMessageClass();
// /////////////////////////////////////////////////
/******************** 事件消息 ********************/
// /////////////////////////////////////////////////
initEventMessageClass();
// /////////////////////////////////////////////////
/***************** 公众平台事件消息 *****************/
// /////////////////////////////////////////////////
initMpEventMessageClass();
// /////////////////////////////////////////////////
/****************** 企业号事件消息 ******************/
// /////////////////////////////////////////////////
initQyEventMessageClass();
}
private void initGeneralMessageClass() {
for (AccountType accountType : AccountType.values()) {
messageClassMap.put(new MessageKey(MessageType.text.name(), null,
accountType), TextMessage.class);
messageClassMap.put(new MessageKey(MessageType.image.name(), null,
accountType), ImageMessage.class);
messageClassMap.put(new MessageKey(MessageType.voice.name(), null,
accountType), VoiceMessage.class);
messageClassMap.put(new MessageKey(MessageType.video.name(), null,
accountType), VideoMessage.class);
messageClassMap.put(new MessageKey(MessageType.shortvideo.name(),
null, accountType), VideoMessage.class);
messageClassMap.put(new MessageKey(MessageType.location.name(),
null, accountType), LocationMessage.class);
messageClassMap.put(new MessageKey(MessageType.link.name(), null,
accountType), LinkMessage.class);
}
}
private void initEventMessageClass() {
String messageType = MessageType.event.name();
EventType[] eventTypes = new EventType[] { EventType.subscribe,
EventType.unsubscribe };
for (EventType eventType : eventTypes) {
messageClassMap.put(new MessageKey(messageType, eventType.name(),
AccountType.MP),
com.foxinmy.weixin4j.mp.event.ScribeEventMessage.class);
}
for (EventType eventType : eventTypes) {
messageClassMap.put(new MessageKey(messageType, eventType.name(),
AccountType.QY),
com.foxinmy.weixin4j.qy.event.ScribeEventMessage.class);
}
for (AccountType accountType : AccountType.values()) {
messageClassMap.put(
new MessageKey(messageType, EventType.location.name(),
accountType), LocationEventMessage.class);
messageClassMap.put(new MessageKey(messageType,
EventType.location_select.name(), accountType),
MenuLocationEventMessage.class);
for (EventType eventType : new EventType[] { EventType.click,
EventType.view }) {
messageClassMap.put(
new MessageKey(messageType, eventType.name(),
accountType), MenuEventMessage.class);
}
for (EventType eventType : new EventType[] {
EventType.scancode_push, EventType.scancode_waitmsg }) {
messageClassMap.put(
new MessageKey(messageType, eventType.name(),
accountType), MenuScanEventMessage.class);
}
for (EventType eventType : new EventType[] {
EventType.pic_sysphoto, EventType.pic_photo_or_album,
EventType.pic_weixin }) {
messageClassMap.put(
new MessageKey(messageType, eventType.name(),
accountType), MenuPhotoEventMessage.class);
}
}
}
private void initMpEventMessageClass() {
String messageType = MessageType.event.name();
AccountType accountType = AccountType.MP;
messageClassMap.put(new MessageKey(messageType, EventType.scan.name(),
accountType),
com.foxinmy.weixin4j.mp.event.ScanEventMessage.class);
messageClassMap.put(new MessageKey(messageType,
EventType.masssendjobfinish.name(), accountType),
MassEventMessage.class);
messageClassMap.put(new MessageKey(messageType,
EventType.templatesendjobfinish.name(), accountType),
TemplatesendjobfinishMessage.class);
messageClassMap.put(new MessageKey(messageType,
EventType.kf_create_session.name(), accountType),
KfCreateEventMessage.class);
messageClassMap.put(new MessageKey(messageType,
EventType.kf_close_session.name(), accountType),
KfCloseEventMessage.class);
messageClassMap.put(new MessageKey(messageType,
EventType.kf_switch_session.name(), accountType),
KfSwitchEventMessage.class);
}
private void initQyEventMessageClass() {
String messageType = MessageType.event.name();
AccountType accountType = AccountType.QY;
messageClassMap.put(new MessageKey(messageType,
EventType.batch_job_result.name(), accountType),
BatchjobresultMessage.class);
messageClassMap.put(
new MessageKey(messageType, EventType.enter_agent.name(),
accountType), EnterAgentEventMessage.class);
}
@Override
public Class<?> match(MessageKey messageKey) {
return messageClassMap.get(messageKey);
}
@Override
public void regist(MessageKey messageKey, Class<?> messageClass) {
Class<?> clazz = messageClassMap.get(messageKey);
if (clazz != null) {
throw new IllegalArgumentException("duplicate messagekey '"
+ messageKey + "' define for " + clazz);
}
messageClassMap.put(messageKey, messageClass);
}
}

View File

@ -0,0 +1,88 @@
package com.foxinmy.weixin4j.dispatcher;
import java.io.Serializable;
import com.foxinmy.weixin4j.type.AccountType;
import com.foxinmy.weixin4j.util.StringUtil;
/**
* 微信消息key
*
* @className MessageKey
* @author jy
* @date 2015年6月9日
* @since JDK 1.7
* @see
*/
public class MessageKey implements Serializable {
private static final long serialVersionUID = -691330687850400289L;
private String messageType;
private String eventType;
private AccountType accountType;
public MessageKey(String messageType, String eventType,
AccountType accountType) {
this.messageType = messageType;
this.eventType = eventType;
this.accountType = accountType;
}
public String getMessageType() {
return messageType;
}
public String getEventType() {
return eventType;
}
public AccountType getAccountType() {
return accountType;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((accountType == null) ? 0 : accountType.hashCode());
result = prime * result
+ ((StringUtil.isBlank(eventType)) ? 0 : eventType.hashCode());
result = prime
* result
+ ((StringUtil.isBlank(messageType)) ? 0 : messageType
.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MessageKey other = (MessageKey) obj;
if (accountType != other.accountType)
return false;
if (eventType == null) {
if (other.eventType != null)
return false;
} else if (!eventType.equalsIgnoreCase(other.eventType))
return false;
if (messageType == null) {
if (other.messageType != null)
return false;
} else if (!messageType.equalsIgnoreCase(other.messageType))
return false;
return true;
}
@Override
public String toString() {
return "MessageKey [messageType=" + messageType + ", eventType="
+ eventType + ", accountType=" + accountType + "]";
}
}

View File

@ -27,11 +27,8 @@ import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.handler.MessageHandlerAdapter; import com.foxinmy.weixin4j.handler.MessageHandlerAdapter;
import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.handler.WeixinMessageHandler;
import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor; import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor;
import com.foxinmy.weixin4j.messagekey.DefaultMessageKeyDefiner;
import com.foxinmy.weixin4j.messagekey.WeixinMessageKeyDefiner;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.response.WeixinResponse;
import com.foxinmy.weixin4j.type.AccountType;
import com.foxinmy.weixin4j.util.ClassUtil; import com.foxinmy.weixin4j.util.ClassUtil;
import com.foxinmy.weixin4j.util.Consts; import com.foxinmy.weixin4j.util.Consts;
import com.foxinmy.weixin4j.util.HttpUtil; import com.foxinmy.weixin4j.util.HttpUtil;
@ -48,7 +45,6 @@ import com.foxinmy.weixin4j.xml.CruxMessageHandler;
* @see com.foxinmy.weixin4j.handler.WeixinMessageHandler * @see com.foxinmy.weixin4j.handler.WeixinMessageHandler
* @see com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor * @see com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor
* @see com.foxinmy.weixin4j.dispatcher.WeixinMessageMatcher * @see com.foxinmy.weixin4j.dispatcher.WeixinMessageMatcher
* @see com.foxinmy.weixin4j.messagekey.WeixinMessageKeyDefiner
* @see com.foxinmy.weixin4j.dispatcher.MessageHandlerExecutor * @see com.foxinmy.weixin4j.dispatcher.MessageHandlerExecutor
* @see com.foxinmy.weixin4j.dispatcher.BeanFactory * @see com.foxinmy.weixin4j.dispatcher.BeanFactory
*/ */
@ -86,23 +82,18 @@ public class WeixinMessageDispatcher {
* 消息匹配 * 消息匹配
*/ */
private WeixinMessageMatcher messageMatcher; private WeixinMessageMatcher messageMatcher;
/**
* 消息key
*/
private WeixinMessageKeyDefiner messageKeyDefiner;
/** /**
* 消息转换 * 消息转换
*/ */
private Map<Class<?>, Unmarshaller> messageUnmarshaller; private Map<Class<?>, Unmarshaller> messageUnmarshaller;
public WeixinMessageDispatcher() { public WeixinMessageDispatcher() {
this(new DefaultMessageKeyDefiner()); this(new DefaultMessageMatcher());
} }
public WeixinMessageDispatcher(WeixinMessageKeyDefiner messageKeyDefiner) { public WeixinMessageDispatcher(WeixinMessageMatcher messageMatcher) {
messageMatcher = new WeixinMessageMatcher(messageKeyDefiner); this.messageMatcher = messageMatcher;
messageUnmarshaller = new HashMap<Class<?>, Unmarshaller>(); this.messageUnmarshaller = new HashMap<Class<?>, Unmarshaller>();
this.messageKeyDefiner = messageKeyDefiner;
} }
/** /**
@ -119,16 +110,15 @@ public class WeixinMessageDispatcher {
public void doDispatch(final ChannelHandlerContext context, public void doDispatch(final ChannelHandlerContext context,
final WeixinRequest request, final CruxMessageHandler cruxMessage) final WeixinRequest request, final CruxMessageHandler cruxMessage)
throws WeixinException { throws WeixinException {
String messageKey = messageKeyDefiner.defineMessageKey( MessageKey messageKey = new MessageKey(cruxMessage.getMsgType(),
cruxMessage.getMsgType(), cruxMessage.getEventType(), cruxMessage.getEventType(), cruxMessage.getAccountType());
cruxMessage.getAccountType()); Class<?> targetClass = messageMatcher.match(messageKey);
Class<?> targetClass = messageMatcher.find(messageKey);
Object message = request.getOriginalContent(); Object message = request.getOriginalContent();
if (targetClass != null) { if (targetClass != null) {
message = messageRead(request.getOriginalContent(), targetClass); message = messageRead(request.getOriginalContent(), targetClass);
} }
logger.info("define [{}] messageKey matched [{}] unmarshal to {}", logger.info("define '{}' matched '{}'", messageKey,
messageKey, targetClass, message); targetClass);
MessageHandlerExecutor handlerExecutor = getHandlerExecutor(context, MessageHandlerExecutor handlerExecutor = getHandlerExecutor(context,
request, messageKey, message); request, messageKey, message);
if (handlerExecutor == null if (handlerExecutor == null
@ -186,7 +176,7 @@ public class WeixinMessageDispatcher {
*/ */
protected MessageHandlerExecutor getHandlerExecutor( protected MessageHandlerExecutor getHandlerExecutor(
ChannelHandlerContext context, WeixinRequest request, ChannelHandlerContext context, WeixinRequest request,
String messageKey, Object message) throws WeixinException { MessageKey messageKey, Object message) throws WeixinException {
WeixinMessageHandler messageHandler = null; WeixinMessageHandler messageHandler = null;
WeixinMessageHandler[] messageHandlers = getMessageHandlers(); WeixinMessageHandler[] messageHandlers = getMessageHandlers();
if (messageHandlers == null) { if (messageHandlers == null) {
@ -195,11 +185,6 @@ public class WeixinMessageDispatcher {
for (WeixinMessageHandler handler : messageHandlers) { for (WeixinMessageHandler handler : messageHandlers) {
if (handler instanceof MessageHandlerAdapter) { if (handler instanceof MessageHandlerAdapter) {
Class<?> genericType = genericTypeRead(handler); Class<?> genericType = genericTypeRead(handler);
if (!messageMatcher.match(genericType)) {
message = messageRead(request.getOriginalContent(),
genericType);
messageMatcher.regist(messageKey, genericType);
}
if (genericType == message.getClass() if (genericType == message.getClass()
&& handler.canHandle(request, message)) { && handler.canHandle(request, message)) {
messageHandler = handler; messageHandler = handler;
@ -268,7 +253,6 @@ public class WeixinMessageDispatcher {
} }
} }
return this.messageHandlers; return this.messageHandlers;
} }
/** /**
@ -421,21 +405,11 @@ public class WeixinMessageDispatcher {
this.beanFactory = beanFactory; this.beanFactory = beanFactory;
} }
public void registMessageMatch(String messageType, String eventType, public void registMessageClass(MessageKey messageKey, Class<?> messageClass) {
AccountType accountType, Class<?> messageClass) {
registMessageMatch(messageKeyDefiner.defineMessageKey(messageType,
eventType, accountType), messageClass);
}
public void registMessageMatch(String messageKey, Class<?> messageClass) {
messageMatcher.regist(messageKey, messageClass); messageMatcher.regist(messageKey, messageClass);
} }
public WeixinMessageMatcher getMessageMatcher() { public WeixinMessageMatcher getMessageMatcher() {
return this.messageMatcher; return this.messageMatcher;
} }
public WeixinMessageKeyDefiner getMessageKeyDefiner() {
return this.messageKeyDefiner;
}
} }

View File

@ -0,0 +1,31 @@
package com.foxinmy.weixin4j.dispatcher;
/**
* 微信消息匹配
*
* @className WeixinMessageMatcher
* @author jy
* @date 2015年5月17日
* @since JDK 1.7
* @see DefaultMessageMatcher
*/
public interface WeixinMessageMatcher {
/**
* 匹配消息类型
*
* @param messageKey
* 消息key
* @return 消息类型
*/
public Class<?> match(MessageKey messageKey);
/**
* 注册消息类型程序没有及时更新而微信又产生了新的消息类型
*
* @param messageKey
* 消息key
* @param messageClass
* 消息类型
*/
public void regist(MessageKey messageKey, Class<?> messageClass);
}

View File

@ -1,45 +0,0 @@
package com.foxinmy.weixin4j.messagekey;
import com.foxinmy.weixin4j.type.AccountType;
import com.foxinmy.weixin4j.type.MessageType;
import com.foxinmy.weixin4j.util.StringUtil;
/**
* 默认的messageKey实现
*
* <p>
* 普通消息key=messageType.toLowerCase();</br>
* 事件消息key=accountType:eventType:messageType.toLowerCase();
* </p>
*
* @className DefaultMessageKeyDefiner
* @author jy
* @date 2015年5月18日
* @since JDK 1.7
* @see
*/
public class DefaultMessageKeyDefiner implements WeixinMessageKeyDefiner {
private static final String MESSAGEKEY_SEPARATOR = ":";
@Override
public String defineMessageKey(String messageType, String eventType,
AccountType accountType) {
StringBuilder messageKey = new StringBuilder();
if (!StringUtil.isBlank(messageType)) {
messageKey.append(messageType.toLowerCase());
if (!messageType.trim().equalsIgnoreCase(MessageType.event.name())) {
return messageKey.toString();
}
}
if (accountType != null) {
messageKey.insert(0, String.format("%s%s", accountType.name()
.toLowerCase(), MESSAGEKEY_SEPARATOR));
}
if (!StringUtil.isBlank(eventType)) {
messageKey.append(MESSAGEKEY_SEPARATOR).append(
eventType.toLowerCase());
}
return messageKey.toString();
}
}

View File

@ -1,29 +0,0 @@
package com.foxinmy.weixin4j.messagekey;
import com.foxinmy.weixin4j.type.AccountType;
/**
* 微信消息key的定义
*
* @className WeixinMessageKeyDefiner
* @author jy
* @date 2015年5月18日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.messagekey.DefaultMessageKeyDefiner
*/
public interface WeixinMessageKeyDefiner {
/**
* 声明messageKey
*
* @param messageType
* 消息类型
* @param eventType
* 事件类型
* @param accountType
* 账号类型
* @return messageKey
*/
public String defineMessageKey(String messageType, String eventType,
AccountType accountType);
}

View File

@ -1,42 +0,0 @@
package com.foxinmy.weixin4j.messagekey;
/**
* 微信消息匹配
*
* @className WeixinMessageMatcher
* @author jy
* @date 2015年5月17日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.request.WeixinMessage
* @see com.foxinmy.weixin4j.messagekey.WeixinMessageKeyDefiner
*/
public interface WeixinMessageMatcher {
/**
* 消息是否匹配
*
* @param messageKeyOrMessageClass
* 消息key或者消息类型
* @return 匹配结果
*/
public boolean match(Object messageKeyOrMessageClass);
/**
* 匹配到消息类型
*
* @param messageKey
* 消息key
* @return 消息类型
*/
public Class<?> match(String messageKey);
/**
* 注册messageClass
*
* @param messageKey
* 消息key
* @param messageClass
* 消息类型
*/
public void regist(String messageKey, Class<?> messageClass);
}

View File

@ -50,7 +50,7 @@ public class WeixinRequestHandler extends
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ctx.close(); ctx.close();
logger.error("catch the exception:{}", cause.getMessage()); logger.error("catch the exception:{}", cause);
} }
@Override @Override

View File

@ -15,14 +15,14 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import com.foxinmy.weixin4j.dispatcher.BeanFactory; import com.foxinmy.weixin4j.dispatcher.BeanFactory;
import com.foxinmy.weixin4j.dispatcher.DefaultMessageMatcher;
import com.foxinmy.weixin4j.dispatcher.MessageKey;
import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher; import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher;
import com.foxinmy.weixin4j.dispatcher.WeixinMessageMatcher;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.handler.WeixinMessageHandler;
import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor; import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor;
import com.foxinmy.weixin4j.messagekey.DefaultMessageKeyDefiner;
import com.foxinmy.weixin4j.messagekey.WeixinMessageKeyDefiner;
import com.foxinmy.weixin4j.socket.WeixinServerInitializer; import com.foxinmy.weixin4j.socket.WeixinServerInitializer;
import com.foxinmy.weixin4j.type.AccountType;
import com.foxinmy.weixin4j.util.AesToken; import com.foxinmy.weixin4j.util.AesToken;
/** /**
@ -100,15 +100,15 @@ public final class WeixinServerBootstrap {
} }
public WeixinServerBootstrap(AesToken aesToken) { public WeixinServerBootstrap(AesToken aesToken) {
this(aesToken, new DefaultMessageKeyDefiner()); this(aesToken, new DefaultMessageMatcher());
} }
public WeixinServerBootstrap(AesToken aesToken, public WeixinServerBootstrap(AesToken aesToken,
WeixinMessageKeyDefiner messageKeyDefiner) { WeixinMessageMatcher messageMatcher) {
this.aesToken = aesToken; this.aesToken = aesToken;
this.messageHandlerList = new LinkedList<WeixinMessageHandler>(); this.messageHandlerList = new LinkedList<WeixinMessageHandler>();
this.messageInterceptorList = new LinkedList<WeixinMessageInterceptor>(); this.messageInterceptorList = new LinkedList<WeixinMessageInterceptor>();
this.messageDispatcher = new WeixinMessageDispatcher(messageKeyDefiner); this.messageDispatcher = new WeixinMessageDispatcher(messageMatcher);
} }
/** /**
@ -251,40 +251,18 @@ public final class WeixinServerBootstrap {
return this; return this;
} }
/**
* 注册消息类型
*
* @param messageType
* 消息类型
* @param eventType
* 事件类型
* @param accountType
* 账号类型
* @param messageClass
* 消息类
* @see com.foxinmy.weixin4j.messagekey.WeixinMessageKeyDefiner
* @return
*/
public WeixinServerBootstrap registMessageClass(String messageType,
String eventType, AccountType accountType, Class<?> messageClass) {
messageDispatcher.registMessageMatch(messageType, eventType,
accountType, messageClass);
return this;
}
/** /**
* 注册消息类型 * 注册消息类型
* *
* @param messageKey * @param messageKey
* 消息key * 消息key
* @param messageClass * @param messageClass
* 消息类 * 消息类
* @see com.foxinmy.weixin4j.messagekey.WeixinMessageKeyDefiner
* @return * @return
*/ */
public WeixinServerBootstrap registMessageClass(String messageKey, public WeixinServerBootstrap registMessageClass(MessageKey messageKey,
Class<?> messageClass) { Class<?> messageClass) {
messageDispatcher.registMessageMatch(messageKey, messageClass); messageDispatcher.registMessageClass(messageKey, messageClass);
return this; return this;
} }
} }

View File

@ -109,6 +109,6 @@ public class MessageServerStartup {
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
new MessageServerStartup().test1(); new MessageServerStartup().test3();
} }
} }