From 67d87a0a69bf202bc4437ee4659d9b2c3f04f29d Mon Sep 17 00:00:00 2001 From: jinyu Date: Sat, 16 May 2015 18:36:16 +0800 Subject: [PATCH] =?UTF-8?q?weixin4j-server:=E5=AE=9E=E7=8E=B0=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E5=A4=84=E7=90=86=E5=99=A8=E7=9A=84=E6=B3=9B=E5=9E=8B?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGE.md | 4 + weixin4j-server/CHANGE.md | 6 +- weixin4j-server/README.md | 28 ++- .../dispatcher/MessageHandlerExecutor.java | 6 +- .../dispatcher/WeixinMessageAdapter.java | 69 ------- .../dispatcher/WeixinMessageDispatcher.java | 103 +++++++++- .../dispatcher/WeixinMessageMatcher.java | 177 ++++++++++++++++++ .../weixin4j/handler/BlankMessageHandler.java | 4 +- .../weixin4j/handler/DebugMessageHandler.java | 6 +- .../handler/MessageHandlerAdapter.java | 26 ++- .../handler/WeixinMessageHandler.java | 4 +- .../MessageInterceptorAdapter.java | 34 +--- .../interceptor/WeixinMessageInterceptor.java | 6 +- .../weixin4j/socket/WeixinRequestHandler.java | 33 +--- .../com/foxinmy/weixin4j/type/EventType.java | 29 +-- .../com/foxinmy/weixin4j/util/ClassUtil.java | 3 +- .../weixin4j/xml/CruxMessageHandler.java | 95 ++++++++++ .../weixin4j/xml/EncryptMessageHandler.java | 13 +- .../server/test/MessageServerStartup.java | 18 +- 19 files changed, 456 insertions(+), 208 deletions(-) delete mode 100644 weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/WeixinMessageAdapter.java create mode 100644 weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/WeixinMessageMatcher.java create mode 100644 weixin4j-server/src/main/java/com/foxinmy/weixin4j/xml/CruxMessageHandler.java diff --git a/CHANGE.md b/CHANGE.md index c1402f89..96326c24 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -284,3 +284,7 @@ * 2015-05-15 + **weixin4j-server**: 消息拦截器和处理器支持泛型 + +* 2015-05-16 + + + **weixin4j-server**: 实现消息处理器的泛型自动匹配 diff --git a/weixin4j-server/CHANGE.md b/weixin4j-server/CHANGE.md index effc0e53..daac30aa 100644 --- a/weixin4j-server/CHANGE.md +++ b/weixin4j-server/CHANGE.md @@ -32,4 +32,8 @@ * 2015-05-15 - + **weixin4j-server**: 消息拦截器和处理器支持泛型 \ No newline at end of file + + 消息拦截器和处理器支持泛型 + +* 2015-05-16 + + + 实现消息处理器的泛型自动匹配 \ No newline at end of file diff --git a/weixin4j-server/README.md b/weixin4j-server/README.md index 72199d7c..fef12ac6 100644 --- a/weixin4j-server/README.md +++ b/weixin4j-server/README.md @@ -37,23 +37,18 @@ weixin4j-server public class MessageServerStartup{ public static void main(String[] args) { - // 需要一个文本消息的handler - WeixinMessageHandler messageHandler = new WeixinMessageHandler() { + // 针对文本消息回复 + WeixinMessageHandler messageHandler = new MessageHandlerAdapter() { @Override - public WeixinResponse doHandle(WeixinRequest request, - WeixinMessage message) throws WeixinException { - return new TextResponse("HelloWorld!"); - } - - @Override - public boolean canHandle(WeixinRequest request, - WeixinMessage message) { - return message.getMsgType().equals("text"); + public WeixinResponse doHandle0(WeixinRequest request, + TextMessage message) throws WeixinException { + return new TextResponse("HelloWorld!"); } }; // 当消息类型为文本(text)时回复「HelloWorld」, 否则回复调试消息 - new WeixinServerBootstrap("appid","开发者token","加密密钥").addHandler(messageHandler, - DebugMessageHandler.global).startup(); + new WeixinServerBootstrap(appid, token, aesKey).addHandler( + messageHandler, DebugMessageHandler.global).startup(); + } } } 编写一个拦截器 @@ -63,22 +58,21 @@ weixin4j-server WeixinMessageInterceptor interceptor = new MessageInterceptorAdapter() { @Override public boolean preHandle(ChannelHandlerContext context, - WeixinRequest request, WeixinMessage message, + WeixinRequest request, Object message, WeixinMessageHandler handler) throws WeixinException { context.write(new TextResponse("所有消息被拦截了!")); return false; } - @Override public void postHandle(ChannelHandlerContext context, WeixinRequest request, WeixinResponse response, - WeixinMessage message, WeixinMessageHandler handler) + Object message, WeixinMessageHandler handler) throws WeixinException { System.err.println("preHandle返回为true,执行handler后"); } @Override public void afterCompletion(ChannelHandlerContext context, - WeixinRequest request, WeixinMessage message, + WeixinRequest request, Object message, WeixinMessageHandler handler, WeixinException exception) throws WeixinException { System.err.println("请求处理完毕"); diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/MessageHandlerExecutor.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/MessageHandlerExecutor.java index 18481c02..7b5a90fb 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/MessageHandlerExecutor.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/MessageHandlerExecutor.java @@ -48,7 +48,7 @@ public class MessageHandlerExecutor { return messageHandler; } - public boolean applyPreHandle(WeixinRequest request, String message) + public boolean applyPreHandle(WeixinRequest request, Object message) throws WeixinException { if (messageInterceptors != null) { for (int i = 0; i < messageInterceptors.length; i++) { @@ -65,7 +65,7 @@ public class MessageHandlerExecutor { } public void applyPostHandle(WeixinRequest request, WeixinResponse response, - String message) throws WeixinException { + Object message) throws WeixinException { if (messageInterceptors == null) { return; } @@ -76,7 +76,7 @@ public class MessageHandlerExecutor { } } - public void triggerAfterCompletion(WeixinRequest request, String message, + public void triggerAfterCompletion(WeixinRequest request, Object message, WeixinException exception) throws WeixinException { if (messageInterceptors == null) { return; diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/WeixinMessageAdapter.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/WeixinMessageAdapter.java deleted file mode 100644 index 94bbc936..00000000 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/WeixinMessageAdapter.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.foxinmy.weixin4j.dispatcher; - -import java.io.ByteArrayInputStream; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBElement; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Unmarshaller; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - -import com.foxinmy.weixin4j.exception.WeixinException; -import com.foxinmy.weixin4j.request.WeixinMessage; -import com.foxinmy.weixin4j.util.Consts; - -public abstract class WeixinMessageAdapter { - /** - * 消息类集合 - */ - private static final Map, Unmarshaller> unmarshallerMap; - - static { - unmarshallerMap = new HashMap, Unmarshaller>(); - } - - @SuppressWarnings("unchecked") - protected M messageRead(String message) throws WeixinException { - try { - Class clazz = resolveMessageClass(); - Source source = new StreamSource(new ByteArrayInputStream( - message.getBytes(Consts.UTF_8))); - JAXBElement jaxbElement = getUnmarshaller().unmarshal(source, - clazz); - return (M) jaxbElement.getValue(); - } catch (JAXBException e) { - throw new WeixinException(e); - } - } - - protected Unmarshaller getUnmarshaller() throws WeixinException { - Class mineClass = resolveMessageClass(); - Unmarshaller unmarshaller = unmarshallerMap.get(mineClass); - if (unmarshaller == null) { - try { - JAXBContext jaxbContext = JAXBContext.newInstance(mineClass); - unmarshaller = jaxbContext.createUnmarshaller(); - unmarshallerMap.put(mineClass, unmarshaller); - } catch (JAXBException e) { - throw new WeixinException(e); - } - } - return unmarshaller; - } - - protected Class resolveMessageClass() { - Class clazz = WeixinMessage.class; - Type type = getClass().getGenericSuperclass(); - if (type instanceof ParameterizedType) { - ParameterizedType ptype = ((ParameterizedType) type); - Type[] args = ptype.getActualTypeArguments(); - clazz = (Class) args[0]; - } - return clazz; - } -} diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/WeixinMessageDispatcher.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/WeixinMessageDispatcher.java index 837c80ff..e64fa424 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/WeixinMessageDispatcher.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/WeixinMessageDispatcher.java @@ -4,21 +4,35 @@ import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; +import java.io.ByteArrayInputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.foxinmy.weixin4j.bean.BeanFactory; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.handler.MessageHandlerAdapter; import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor; import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.util.ClassUtil; +import com.foxinmy.weixin4j.util.Consts; import com.foxinmy.weixin4j.util.HttpUtil; import com.foxinmy.weixin4j.util.ReflectionUtil; @@ -60,14 +74,30 @@ public class WeixinMessageDispatcher { */ private BeanFactory beanFactory; + /** + * 消息匹配 + */ + private WeixinMessageMatcher messageMatcher; + /** + * 消息转换 + */ + private Map, Unmarshaller> messageUnmarshaller; + public WeixinMessageDispatcher() { + messageMatcher = new WeixinMessageMatcher(); + messageUnmarshaller = new HashMap, Unmarshaller>(); } public void doDispatch(final ChannelHandlerContext context, - final WeixinRequest request, final String message) + final WeixinRequest request, final String uniqueKey) throws WeixinException { + Class targetClass = messageMatcher.find(uniqueKey); + Object message = request.getOriginalContent(); + if (targetClass != null) { + message = messageRead(request.getOriginalContent(), targetClass); + } MessageHandlerExecutor handlerExecutor = getHandlerExecutor(context, - request, message); + request, uniqueKey, message); if (handlerExecutor == null || handlerExecutor.getMessageHandler() == null) { noHandlerFound(context, request, message); @@ -93,23 +123,41 @@ public class WeixinMessageDispatcher { } protected void noHandlerFound(ChannelHandlerContext ctx, - WeixinRequest request, String message) { + WeixinRequest request, Object message) { ctx.writeAndFlush(HttpUtil.createHttpResponse(null, NOT_FOUND, null)) .addListener(ChannelFutureListener.CLOSE); } protected MessageHandlerExecutor getHandlerExecutor( - ChannelHandlerContext context, WeixinRequest request, String message) - throws WeixinException { + ChannelHandlerContext context, WeixinRequest request, + String uniqueKey, Object message) throws WeixinException { WeixinMessageHandler messageHandler = null; WeixinMessageHandler[] messageHandlers = getMessageHandlers(); if (messageHandlers == null) { return null; } for (WeixinMessageHandler handler : messageHandlers) { - if (handler.canHandle(request, message)) { - messageHandler = handler; - break; + if (handler instanceof MessageHandlerAdapter) { + Class genericType = genericTypeRead(handler); + if (!messageMatcher.match(genericType)) { + message = messageRead(request.getOriginalContent(), + genericType); + messageMatcher.regist(uniqueKey, genericType); + } + if (genericType == message.getClass() + && handler.canHandle(request, message)) { + messageHandler = handler; + break; + } + } + } + if (messageHandler == null) { + for (WeixinMessageHandler handler : messageHandlers) { + if (!(handler instanceof MessageHandlerAdapter) + && handler.canHandle(request, message)) { + messageHandler = handler; + break; + } } } return new MessageHandlerExecutor(context, messageHandler, @@ -205,6 +253,45 @@ public class WeixinMessageDispatcher { return this.messageInterceptors; } + protected Object messageRead(String message, Class clazz) + throws WeixinException { + try { + Source source = new StreamSource(new ByteArrayInputStream( + message.getBytes(Consts.UTF_8))); + JAXBElement jaxbElement = getUnmarshaller(clazz).unmarshal( + source, clazz); + return jaxbElement.getValue(); + } catch (JAXBException e) { + throw new WeixinException(e); + } + } + + protected Unmarshaller getUnmarshaller(Class clazz) + throws WeixinException { + Unmarshaller unmarshaller = messageUnmarshaller.get(clazz); + if (unmarshaller == null) { + try { + JAXBContext jaxbContext = JAXBContext.newInstance(clazz); + unmarshaller = jaxbContext.createUnmarshaller(); + messageUnmarshaller.put(clazz, unmarshaller); + } catch (JAXBException e) { + throw new WeixinException(e); + } + } + return unmarshaller; + } + + private Class genericTypeRead(Object object) { + Class clazz = null; + Type type = object.getClass().getGenericSuperclass(); + if (type instanceof ParameterizedType) { + ParameterizedType ptype = ((ParameterizedType) type); + Type[] args = ptype.getActualTypeArguments(); + clazz = (Class) args[0]; + } + return clazz; + } + public void setMessageHandlerList( List messageHandlerList) { this.messageHandlerList = messageHandlerList; diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/WeixinMessageMatcher.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/WeixinMessageMatcher.java new file mode 100644 index 00000000..dd8b3c59 --- /dev/null +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/WeixinMessageMatcher.java @@ -0,0 +1,177 @@ +package com.foxinmy.weixin4j.dispatcher; + +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.foxinmy.weixin4j.message.ImageMessage; +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.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.ScanEventMessage; +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.EventType; +import com.foxinmy.weixin4j.type.MessageType; + +public class WeixinMessageMatcher { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private final String MP_TAG = "mp"; + private final String QY_TAG = "qy"; + + private final Map> key2ClassMap; + private final Map, String> class2KeyMap; + + public WeixinMessageMatcher() { + key2ClassMap = new HashMap>(); + class2KeyMap = new HashMap, String>(); + init0(); + init1(); + init2(); + init3(); + log.info("detected message for events: {}", key2ClassMap.keySet()); + } + + private void init0() { + // ///////////////////////////////////////////////// + /******************** 普通消息 ********************/ + // ///////////////////////////////////////////////// + String uniqueKey = MessageType.text.name(); + Class clazz = TextMessage.class; + regist(uniqueKey, clazz); + uniqueKey = MessageType.image.name(); + clazz = ImageMessage.class; + regist(uniqueKey, clazz); + uniqueKey = MessageType.voice.name(); + clazz = VoiceMessage.class; + regist(uniqueKey, clazz); + uniqueKey = MessageType.video.name(); + clazz = VideoMessage.class; + regist(uniqueKey, clazz); + uniqueKey = MessageType.shortvideo.name(); + regist(uniqueKey, clazz); + uniqueKey = MessageType.location.name(); + clazz = LocationMessage.class; + regist(uniqueKey, clazz); + } + + private void init1() { + // ///////////////////////////////////////////////// + /******************** 事件消息 ********************/ + // ///////////////////////////////////////////////// + String uniqueKey; + Class clazz; + for (EventType eventType : new EventType[] { EventType.subscribe, + EventType.unsubscribe }) { + uniqueKey = String.format("%s:%s", MessageType.event.name(), + eventType.name()); + clazz = com.foxinmy.weixin4j.mp.event.ScribeEventMessage.class; + regist(String.format("%s:%s", MP_TAG, uniqueKey), clazz); + } + for (EventType eventType : new EventType[] { EventType.subscribe, + EventType.unsubscribe }) { + uniqueKey = String.format("%s:%s", MessageType.event.name(), + eventType.name()); + clazz = com.foxinmy.weixin4j.qy.event.ScribeEventMessage.class; + regist(String.format("%s:%s", QY_TAG, uniqueKey), clazz); + } + uniqueKey = String.format("%s:%s", MessageType.event.name(), + EventType.location.name()); + clazz = LocationEventMessage.class; + regist(uniqueKey, clazz); + for (EventType eventType : new EventType[] { EventType.click, + EventType.view }) { + uniqueKey = String.format("%s:%s", MessageType.event.name(), + eventType.name()); + clazz = com.foxinmy.weixin4j.message.event.MenuEventMessage.class; + regist(uniqueKey, clazz); + } + for (EventType eventType : new EventType[] { EventType.scancode_push, + EventType.scancode_waitmsg }) { + uniqueKey = String.format("%s:%s", MessageType.event.name(), + eventType.name()); + clazz = com.foxinmy.weixin4j.message.event.MenuScanEventMessage.class; + regist(uniqueKey, clazz); + } + for (EventType eventType : new EventType[] { EventType.pic_sysphoto, + EventType.pic_photo_or_album, EventType.pic_weixin }) { + uniqueKey = String.format("%s:%s", MessageType.event.name(), + eventType.name()); + clazz = com.foxinmy.weixin4j.message.event.MenuPhotoEventMessage.class; + regist(uniqueKey, clazz); + } + uniqueKey = String.format("%s:%s", MessageType.event.name(), + EventType.location_select.name()); + clazz = com.foxinmy.weixin4j.message.event.MenuLocationEventMessage.class; + regist(uniqueKey, clazz); + } + + private void init2() { + // ///////////////////////////////////////////////// + /******************** 公众平台事件消息 ********************/ + // ///////////////////////////////////////////////// + String uniqueKey = String.format("%s:%s:%s", MP_TAG, + MessageType.event.name(), EventType.scan.name()); + Class clazz = ScanEventMessage.class; + regist(uniqueKey, clazz); + uniqueKey = String.format("%s:%s:%s", MP_TAG, MessageType.event.name(), + EventType.masssendjobfinish.name()); + clazz = MassEventMessage.class; + regist(uniqueKey, clazz); + uniqueKey = String.format("%s:%s:%s", MP_TAG, MessageType.event.name(), + EventType.templatesendjobfinish.name()); + clazz = TemplatesendjobfinishMessage.class; + regist(uniqueKey, clazz); + uniqueKey = String.format("%s:%s:%s", MP_TAG, MessageType.event.name(), + EventType.kf_create_session.name()); + clazz = KfCreateEventMessage.class; + regist(uniqueKey, clazz); + uniqueKey = String.format("%s:%s:%s", MP_TAG, MessageType.event.name(), + EventType.kf_close_session.name()); + clazz = KfCloseEventMessage.class; + regist(uniqueKey, clazz); + uniqueKey = String.format("%s:%s:%s", MP_TAG, MessageType.event.name(), + EventType.kf_switch_session.name()); + clazz = KfSwitchEventMessage.class; + regist(uniqueKey, clazz); + } + + private void init3() { + // ///////////////////////////////////////////////// + /******************** 企业号事件消息 ********************/ + // ///////////////////////////////////////////////// + String uniqueKey = String.format("%s:%s:%s", QY_TAG, + MessageType.event.name(), EventType.batch_job_result.name()); + Class clazz = BatchjobresultMessage.class; + regist(uniqueKey, clazz); + uniqueKey = String.format("%s:%s:%s", QY_TAG, MessageType.event.name(), + EventType.enter_agent.name()); + clazz = EnterAgentEventMessage.class; + regist(uniqueKey, clazz); + } + + public void regist(String uniqueKey, Class clazz) { + key2ClassMap.put(uniqueKey, clazz); + class2KeyMap.put(clazz, uniqueKey); + } + + public boolean match(Object keyOrClass) { + return key2ClassMap.containsKey(keyOrClass) + || class2KeyMap.containsKey(keyOrClass); + } + + public Class find(String uniqueKey) { + return key2ClassMap.get(uniqueKey); + } +} diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/BlankMessageHandler.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/BlankMessageHandler.java index b3d152e8..bb069255 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/BlankMessageHandler.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/BlankMessageHandler.java @@ -14,13 +14,13 @@ public class BlankMessageHandler implements WeixinMessageHandler { } @Override - public boolean canHandle(WeixinRequest request, String message) + public boolean canHandle(WeixinRequest request, Object message) throws WeixinException { return true; } @Override - public WeixinResponse doHandle(WeixinRequest request, String message) + public WeixinResponse doHandle(WeixinRequest request, Object message) throws WeixinException { return BlankResponse.global; } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/DebugMessageHandler.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/DebugMessageHandler.java index ac3c86d6..19dc225e 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/DebugMessageHandler.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/DebugMessageHandler.java @@ -14,14 +14,14 @@ public class DebugMessageHandler implements WeixinMessageHandler { } @Override - public boolean canHandle(WeixinRequest request, String message) + public boolean canHandle(WeixinRequest request, Object message) throws WeixinException { return true; } @Override - public WeixinResponse doHandle(WeixinRequest request, String message) + public WeixinResponse doHandle(WeixinRequest request, Object message) throws WeixinException { - return new TextResponse(message); + return new TextResponse(message.toString()); } } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/MessageHandlerAdapter.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/MessageHandlerAdapter.java index 1ca6b422..efc916f9 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/MessageHandlerAdapter.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/MessageHandlerAdapter.java @@ -1,32 +1,30 @@ package com.foxinmy.weixin4j.handler; -import com.foxinmy.weixin4j.dispatcher.WeixinMessageAdapter; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.response.WeixinResponse; -public abstract class MessageHandlerAdapter extends WeixinMessageAdapter - implements WeixinMessageHandler { - - private M message; +@SuppressWarnings("unchecked") +public abstract class MessageHandlerAdapter implements WeixinMessageHandler { @Override - public boolean canHandle(WeixinRequest request, String message) + public boolean canHandle(WeixinRequest request, Object message) throws WeixinException { - this.message = super.messageRead(message); - return canHandle0(request, message, this.message); + return canHandle0(request, (M) message); } - public abstract boolean canHandle0(WeixinRequest request, String message, - M m) throws WeixinException; + public boolean canHandle0(WeixinRequest request, M message) + throws WeixinException { + return true; + } @Override - public WeixinResponse doHandle(WeixinRequest request, String message) + public WeixinResponse doHandle(WeixinRequest request, Object message) throws WeixinException { - return doHandle0(request, message, this.message); + return doHandle0(request, (M) message); } - public abstract WeixinResponse doHandle0(WeixinRequest request, - String message, M m) throws WeixinException; + public abstract WeixinResponse doHandle0(WeixinRequest request, M message) + throws WeixinException; } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/WeixinMessageHandler.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/WeixinMessageHandler.java index cf0da879..96c47368 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/WeixinMessageHandler.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/WeixinMessageHandler.java @@ -24,7 +24,7 @@ public interface WeixinMessageHandler { * 微信消息 * @return */ - public boolean canHandle(WeixinRequest request, String message) + public boolean canHandle(WeixinRequest request, Object message) throws WeixinException; /** @@ -36,6 +36,6 @@ public interface WeixinMessageHandler { * 微信消息 * @return */ - public WeixinResponse doHandle(WeixinRequest request, String message) + public WeixinResponse doHandle(WeixinRequest request, Object message) throws WeixinException; } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/interceptor/MessageInterceptorAdapter.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/interceptor/MessageInterceptorAdapter.java index bd30451c..50881d56 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/interceptor/MessageInterceptorAdapter.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/interceptor/MessageInterceptorAdapter.java @@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.interceptor; import io.netty.channel.ChannelHandlerContext; -import com.foxinmy.weixin4j.dispatcher.WeixinMessageAdapter; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.request.WeixinRequest; @@ -17,45 +16,26 @@ import com.foxinmy.weixin4j.response.WeixinResponse; * @since JDK 1.7 * @see */ -public abstract class MessageInterceptorAdapter extends - WeixinMessageAdapter implements WeixinMessageInterceptor { - - private M message; +public abstract class MessageInterceptorAdapter implements + WeixinMessageInterceptor { @Override public boolean preHandle(ChannelHandlerContext context, - WeixinRequest request, final String message, - WeixinMessageHandler handler) throws WeixinException { - this.message = super.messageRead(message); - return preHandle0(context, request, this.message, handler); + WeixinRequest request, Object message, WeixinMessageHandler handler) + throws WeixinException { + return true; } - public abstract boolean preHandle0(ChannelHandlerContext context, - WeixinRequest request, M message, WeixinMessageHandler handler) - throws WeixinException; - @Override public void postHandle(ChannelHandlerContext context, - WeixinRequest request, WeixinResponse response, String message, + WeixinRequest request, WeixinResponse response, Object message, WeixinMessageHandler handler) throws WeixinException { - postHandle0(context, request, response, message, this.message, handler); } - public abstract void postHandle0(ChannelHandlerContext context, - WeixinRequest request, WeixinResponse response, String message, - M m, WeixinMessageHandler handler) throws WeixinException; - @Override public void afterCompletion(ChannelHandlerContext context, - WeixinRequest request, String message, + WeixinRequest request, Object message, WeixinMessageHandler handler, WeixinException exception) throws WeixinException { - afterCompletion0(context, request, message, this.message, handler, - exception); } - - public abstract void afterCompletion0(ChannelHandlerContext context, - WeixinRequest request, String message, M m, - WeixinMessageHandler handler, WeixinException exception) - throws WeixinException; } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/interceptor/WeixinMessageInterceptor.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/interceptor/WeixinMessageInterceptor.java index b31c3950..b8882e8b 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/interceptor/WeixinMessageInterceptor.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/interceptor/WeixinMessageInterceptor.java @@ -33,7 +33,7 @@ public interface WeixinMessageInterceptor { * @throws WeixinException */ boolean preHandle(ChannelHandlerContext context, WeixinRequest request, - String message, WeixinMessageHandler handler) + Object message, WeixinMessageHandler handler) throws WeixinException; /** @@ -52,7 +52,7 @@ public interface WeixinMessageInterceptor { * @throws WeixinException */ void postHandle(ChannelHandlerContext context, WeixinRequest request, - WeixinResponse response, String message, + WeixinResponse response, Object message, WeixinMessageHandler handler) throws WeixinException; /** @@ -71,6 +71,6 @@ public interface WeixinMessageInterceptor { * @throws WeixinException */ void afterCompletion(ChannelHandlerContext context, WeixinRequest request, - String message, WeixinMessageHandler handler, + Object message, WeixinMessageHandler handler, WeixinException exception) throws WeixinException; } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinRequestHandler.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinRequestHandler.java index 1de9e435..05b12adc 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinRequestHandler.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinRequestHandler.java @@ -8,28 +8,19 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.HttpMethod; -import java.io.ByteArrayInputStream; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBElement; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Unmarshaller; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.foxinmy.weixin4j.bean.AesToken; import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher; import com.foxinmy.weixin4j.exception.WeixinException; -import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.type.EncryptType; import com.foxinmy.weixin4j.util.Consts; import com.foxinmy.weixin4j.util.HttpUtil; import com.foxinmy.weixin4j.util.MessageUtil; import com.foxinmy.weixin4j.util.StringUtil; +import com.foxinmy.weixin4j.xml.CruxMessageHandler; /** * 微信请求处理类 @@ -108,27 +99,17 @@ public class WeixinRequestHandler extends .addListener(ChannelFutureListener.CLOSE); return; } - final String message = request.getOriginalContent(); - WeixinMessage weixinMessage; - try { - Unmarshaller unmarshaller = JAXBContext.newInstance( - WeixinMessage.class).createUnmarshaller(); - Source source = new StreamSource(new ByteArrayInputStream( - message.getBytes())); - JAXBElement jaxbElement = unmarshaller.unmarshal( - source, WeixinMessage.class); - weixinMessage = jaxbElement.getValue(); - } catch (JAXBException e) { - throw new WeixinException(e); - } + CruxMessageHandler messageHandler = CruxMessageHandler.parser(request + .getOriginalContent()); ctx.channel().attr(Consts.ENCRYPTTYPE_KEY) .set(request.getEncryptType()); ctx.channel().attr(Consts.USEROPENID_KEY) - .set(weixinMessage.getFromUserName()); + .set(messageHandler.getFromUserName()); if (StringUtil.isBlank(aesToken.getAppid())) { ctx.channel().attr(Consts.ACCOUNTOPENID_KEY) - .set(weixinMessage.getToUserName()); + .set(messageHandler.getToUserName()); } - messageDispatcher.doDispatch(ctx, request, message); + messageDispatcher.doDispatch(ctx, request, + messageHandler.getUniqueKey()); } } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/type/EventType.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/type/EventType.java index f91233d4..1410af37 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/type/EventType.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/type/EventType.java @@ -26,57 +26,56 @@ public enum EventType { * @see com.foxinmy.weixin4j.message.event.LocationEventMessage */ location, - /** - * 菜单扫描事件 - * - * @see com.foxinmy.weixin4j.message.event.menu.MenuScanEventMessage - */ - scancode_push, /** * 菜单点击关键字事件 * - * @see com.foxinmy.weixin4j.message.event.menu.MenuEventMessage + * @see com.foxinmy.weixin4j.message.event.MenuEventMessage */ view, /** * 菜单点击链接事件 * - * @see com.foxinmy.weixin4j.message.event.menu.MenuEventMessage + * @see com.foxinmy.weixin4j.message.event.MenuEventMessage */ click, + /** + * 菜单扫描事件 + * + * @see com.foxinmy.weixin4j.message.event.MenuScanEventMessage + */ + scancode_push, /** * 菜单扫描并调出等待界面事件 * - * @see com.foxinmy.weixin4j.message.event.menu.MenuScanEventMessage + * @see com.foxinmy.weixin4j.message.event.MenuScanEventMessage */ scancode_waitmsg, /** * 菜单弹出拍照事件 * - * @see com.foxinmy.weixin4j.message.event.menu.MenuPhotoEventMessage + * @see com.foxinmy.weixin4j.message.event.MenuPhotoEventMessage */ pic_sysphoto, /** * 菜单弹出发图事件 * - * @see com.foxinmy.weixin4j.message.event.menu.MenuPhotoEventMessage + * @see com.foxinmy.weixin4j.message.event.MenuPhotoEventMessage */ pic_photo_or_album, /** * 菜单弹出发图事件 * - * @see com.foxinmy.weixin4j.message.event.menu.MenuPhotoEventMessage + * @see com.foxinmy.weixin4j.message.event.MenuPhotoEventMessage */ pic_weixin, /** * 菜单发送地理位置事件 * - * @see com.foxinmy.weixin4j.message.event.menu.MenuLocationEventMessage + * @see com.foxinmy.weixin4j.message.event.MenuLocationEventMessage */ location_select, // ------------------------------公众平台特有------------------------------ - // /** * 二维码扫描事件 @@ -114,6 +113,8 @@ public enum EventType { * @see com.foxinmy.weixin4j.mp.event.KfSwitchEventMessage */ kf_switch_session, + + // ------------------------------企业号特有------------------------------ /** * 异步任务完成事件 * diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/ClassUtil.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/ClassUtil.java index 29657126..48d0214e 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/ClassUtil.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/ClassUtil.java @@ -52,8 +52,7 @@ public final class ClassUtil { throw new RuntimeException(e); } } - throw new UnsupportedOperationException(String.format( - "unknow protocol:", protocol)); + return null; } /** diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/xml/CruxMessageHandler.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/xml/CruxMessageHandler.java new file mode 100644 index 00000000..4d7d823e --- /dev/null +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/xml/CruxMessageHandler.java @@ -0,0 +1,95 @@ +package com.foxinmy.weixin4j.xml; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; +import org.xml.sax.helpers.XMLReaderFactory; + +import com.foxinmy.weixin4j.type.MessageType; +import com.foxinmy.weixin4j.util.Consts; +import com.foxinmy.weixin4j.util.StringUtil; + +public class CruxMessageHandler extends DefaultHandler { + + private String fromUserName; + private String toUserName; + private String msgType; + private String eventType; + private String agentId; + + private String content; + + @Override + public void startDocument() throws SAXException { + fromUserName = null; + toUserName = null; + msgType = null; + eventType = null; + agentId = null; + } + + @Override + public void endElement(String uri, String localName, String qName) + throws SAXException { + if (localName.equalsIgnoreCase("fromUserName")) { + fromUserName = content; + } else if (localName.equalsIgnoreCase("toUserName")) { + toUserName = content; + } else if (localName.equalsIgnoreCase("msgType")) { + msgType = content.toLowerCase(); + } else if (localName.equalsIgnoreCase("event")) { + eventType = content.toLowerCase(); + } else if (localName.equalsIgnoreCase("agentId")) { + agentId = content; + } + } + + @Override + public void characters(char[] ch, int start, int length) + throws SAXException { + this.content = new String(ch, start, length); + } + + public String getUniqueKey() { + StringBuilder uniqueKey = new StringBuilder(); + uniqueKey.append(msgType); + if (msgType.equals(MessageType.event.name())) { + if (StringUtil.isBlank(agentId)) { + uniqueKey.insert(0, "mp:"); + } else { + uniqueKey.insert(0, "qy:"); + } + uniqueKey.append(":").append(eventType); + } + return uniqueKey.toString(); + } + + public String getFromUserName() { + return fromUserName; + } + + public String getToUserName() { + return toUserName; + } + + private static CruxMessageHandler global = new CruxMessageHandler(); + + public static CruxMessageHandler parser(String xmlContent) + throws RuntimeException { + try { + XMLReader xmlReader = XMLReaderFactory.createXMLReader(); + xmlReader.setContentHandler(global); + xmlReader.parse(new InputSource(new ByteArrayInputStream(xmlContent + .getBytes(Consts.UTF_8)))); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (SAXException e) { + throw new RuntimeException(e); + } + return global; + } +} diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/xml/EncryptMessageHandler.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/xml/EncryptMessageHandler.java index 8da8f74a..90e43028 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/xml/EncryptMessageHandler.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/xml/EncryptMessageHandler.java @@ -15,6 +15,7 @@ import com.foxinmy.weixin4j.util.Consts; public class EncryptMessageHandler extends DefaultHandler { private String encryptContent; + private String content; @Override public void startDocument() throws SAXException { @@ -24,28 +25,30 @@ public class EncryptMessageHandler extends DefaultHandler { @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - if (qName.equalsIgnoreCase("encrypt")) { - return; - } + } @Override public void endElement(String uri, String localName, String qName) throws SAXException { + if (localName.equalsIgnoreCase("encrypt")) { + encryptContent = content; + } } @Override public void characters(char[] ch, int start, int length) throws SAXException { - this.encryptContent = new String(ch, start, length); + this.content = new String(ch, start, length); } public String getEncryptContent() { return encryptContent; } + private final static EncryptMessageHandler messageHandler = new EncryptMessageHandler(); + public static String parser(String xmlContent) throws RuntimeException { - EncryptMessageHandler messageHandler = new EncryptMessageHandler(); try { XMLReader xmlReader = XMLReaderFactory.createXMLReader(); xmlReader.setContentHandler(messageHandler); diff --git a/weixin4j-server/src/test/java/com/foxinmy/weixin4j/server/test/MessageServerStartup.java b/weixin4j-server/src/test/java/com/foxinmy/weixin4j/server/test/MessageServerStartup.java index df6f355a..e9ecfdd1 100644 --- a/weixin4j-server/src/test/java/com/foxinmy/weixin4j/server/test/MessageServerStartup.java +++ b/weixin4j-server/src/test/java/com/foxinmy/weixin4j/server/test/MessageServerStartup.java @@ -57,17 +57,11 @@ public class MessageServerStartup { * @throws WeixinException */ public void test3() throws WeixinException { - // 文本消息回复 + // 针对文本消息回复 WeixinMessageHandler messageHandler = new MessageHandlerAdapter() { - @Override - public boolean canHandle0(WeixinRequest request, String message, - TextMessage m) throws WeixinException { - return true; - } - @Override public WeixinResponse doHandle0(WeixinRequest request, - String message, TextMessage m) throws WeixinException { + TextMessage message) throws WeixinException { return new TextResponse("HelloWorld!"); } }; @@ -88,7 +82,7 @@ public class MessageServerStartup { WeixinMessageInterceptor interceptor = new WeixinMessageInterceptor() { @Override public boolean preHandle(ChannelHandlerContext context, - WeixinRequest request, String message, + WeixinRequest request, Object message, WeixinMessageHandler handler) throws WeixinException { context.writeAndFlush(new TextResponse("所有消息被拦截了!")); return false; @@ -97,14 +91,14 @@ public class MessageServerStartup { @Override public void postHandle(ChannelHandlerContext context, WeixinRequest request, WeixinResponse response, - String message, WeixinMessageHandler handler) + Object message, WeixinMessageHandler handler) throws WeixinException { System.err.println("preHandle返回为true,执行handler后"); } @Override public void afterCompletion(ChannelHandlerContext context, - WeixinRequest request, String message, + WeixinRequest request, Object message, WeixinMessageHandler handler, WeixinException exception) throws WeixinException { System.err.println("请求处理完毕"); @@ -115,6 +109,6 @@ public class MessageServerStartup { } public static void main(String[] args) throws WeixinException { - new MessageServerStartup().test1(); + new MessageServerStartup().test5(); } }