diff --git a/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/Weixin4jServerStartupWithThread.java b/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/Weixin4jServerStartupWithThread.java index 1bd271cd..bd2b0c00 100644 --- a/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/Weixin4jServerStartupWithThread.java +++ b/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/Weixin4jServerStartupWithThread.java @@ -66,16 +66,12 @@ public class Weixin4jServerStartupWithThread implements ApplicationContextAware new Thread(new Runnable() { @Override public void run() { - try { - bootstrap = new WeixinServerBootstrap(aesToken) // 指定开发者token信息。 - .handlerPackagesToScan(handlerPackage) // 扫描处理消息的包。 - .resolveBeanFactory(new SpringBeanFactory(applicationContext)) // 声明处理消息类由Spring容器去实例化。 - .addHandler(DebugMessageHandler.global) // 当没有匹配到消息处理时输出调试信息,开发环境打开。 - .openAlwaysResponse(); // 当没有匹配到消息处理时输出空白回复(公众号不会出现「该公众号无法提供服务的提示」),正式环境打开。 - bootstrap.startup(port); // 绑定服务的端口号,即对外暴露(微信服务器URL地址)的服务端口。 - } catch (WeixinException e) { - InternalLoggerFactory.getInstance(getClass()).error("weixin4j server startup:FAIL", e); - } + bootstrap = new WeixinServerBootstrap(aesToken) // 指定开发者token信息。 + .handlerPackagesToScan(handlerPackage) // 扫描处理消息的包。 + .resolveBeanFactory(new SpringBeanFactory(applicationContext)) // 声明处理消息类由Spring容器去实例化。 + .addHandler(DebugMessageHandler.global) // 当没有匹配到消息处理时输出调试信息,开发环境打开。 + .openAlwaysResponse(); // 当没有匹配到消息处理时输出空白回复(公众号不会出现「该公众号无法提供服务的提示」),正式环境打开。 + bootstrap.startup(port); // 绑定服务的端口号,即对外暴露(微信服务器URL地址)的服务端口。 } }).start(); } diff --git a/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/ChatMessageHandler.java b/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/ChatMessageHandler.java index 2fb7f104..97c025cf 100644 --- a/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/ChatMessageHandler.java +++ b/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/ChatMessageHandler.java @@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.example.server.handler; import java.util.Set; -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.qy.chat.WeixinChatMessage; import com.foxinmy.weixin4j.request.WeixinMessage; @@ -12,22 +11,19 @@ import com.foxinmy.weixin4j.response.WeixinResponse; public class ChatMessageHandler implements WeixinMessageHandler { - @Override - public boolean canHandle(WeixinRequest request, WeixinMessage message, - Set nodeNames) throws WeixinException { - return nodeNames.contains("PackageId"); - } + @Override + public boolean canHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) { + return nodeNames.contains("PackageId"); + } - @Override - public WeixinResponse doHandle(WeixinRequest request, - WeixinMessage message, Set nodeNames) - throws WeixinException { - WeixinChatMessage chatMessage = null; // 转换为实体 - return BlankResponse.global; - } + @Override + public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) { + WeixinChatMessage chatMessage = null; // 转换为实体 + return BlankResponse.global; + } - @Override - public int weight() { - return 0; - } + @Override + public int weight() { + return 0; + } } diff --git a/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/CustomMessageHandler.java b/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/CustomMessageHandler.java index 4d0119be..682979e6 100644 --- a/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/CustomMessageHandler.java +++ b/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/CustomMessageHandler.java @@ -10,7 +10,8 @@ import com.foxinmy.weixin4j.response.TextResponse; import com.foxinmy.weixin4j.response.WeixinResponse; /** - * 自定义处理消息 + * 自定义处理消息 + * * @className CustomMessageHandler * @author jinyu(foxinmy@gmail.com) * @date 2017年1月19日 @@ -19,22 +20,19 @@ import com.foxinmy.weixin4j.response.WeixinResponse; */ public class CustomMessageHandler implements WeixinMessageHandler { - @Override - public boolean canHandle(WeixinRequest request, WeixinMessage message, - Set nodeNames) throws WeixinException { - // 消息来源某个用户 - return message.getFromUserName().equals("xxx"); - } + @Override + public boolean canHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) { + // 消息来源某个用户 + return message.getFromUserName().equals("xxx"); + } - @Override - public WeixinResponse doHandle(WeixinRequest request, - WeixinMessage message, Set nodeNames) - throws WeixinException { - return new TextResponse("是你,是你,还是你。"); - } + @Override + public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) { + return new TextResponse("是你,是你,还是你。"); + } - @Override - public int weight() { - return 0; - } + @Override + public int weight() { + return 0; + } } diff --git a/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/HelloMessageHandler.java b/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/HelloMessageHandler.java index d8bd60cf..0f78529a 100644 --- a/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/HelloMessageHandler.java +++ b/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/HelloMessageHandler.java @@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.example.server.handler; import org.springframework.stereotype.Component; -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.message.TextMessage; import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.response.TextResponse; @@ -10,7 +9,7 @@ import com.foxinmy.weixin4j.response.WeixinResponse; /** * 输入 hello 回复 world - * + * * @className HelloMessageHandler * @author jinyu(foxinmy@gmail.com) * @date 2015年12月27日 @@ -19,30 +18,28 @@ import com.foxinmy.weixin4j.response.WeixinResponse; @Component public class HelloMessageHandler extends TextMessageHandler { - @Override - public boolean canHandle0(WeixinRequest request, TextMessage message) - throws WeixinException { - /** - * 用户输入hello时 - */ - return message.getContent().equalsIgnoreCase("hello"); - } + @Override + public boolean canHandle0(WeixinRequest request, TextMessage message) { + /** + * 用户输入hello时 + */ + return message.getContent().equalsIgnoreCase("hello"); + } - @Override - public WeixinResponse doHandle0(WeixinRequest request, TextMessage message) - throws WeixinException { - /** - * 返回用户「world」文本 - */ - return new TextResponse("world"); - } + @Override + public WeixinResponse doHandle0(WeixinRequest request, TextMessage message) { + /** + * 返回用户「world」文本 + */ + return new TextResponse("world"); + } - /** - * 因为HelloMessageHandler和TextMessageHandler都会匹配到文本消息 - * 所以这里需要提高下权重(大于TextMessageHandler就行了) > TextMessageHandler - */ - @Override - public int weight() { - return super.weight() + 1; - } + /** + * 因为HelloMessageHandler和TextMessageHandler都会匹配到文本消息 + * 所以这里需要提高下权重(大于TextMessageHandler就行了) > TextMessageHandler + */ + @Override + public int weight() { + return super.weight() + 1; + } } diff --git a/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/SubscribeMessageHandler.java b/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/SubscribeMessageHandler.java index b69ff4d8..da7e54b6 100644 --- a/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/SubscribeMessageHandler.java +++ b/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/SubscribeMessageHandler.java @@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.example.server.handler; import org.springframework.stereotype.Component; -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.handler.MessageHandlerAdapter; import com.foxinmy.weixin4j.mp.event.ScribeEventMessage; import com.foxinmy.weixin4j.request.WeixinRequest; @@ -11,19 +10,17 @@ import com.foxinmy.weixin4j.response.WeixinResponse; /** * 处理关注消息 - * + * * @className SubscribeMessageHandler * @author jinyu(foxinmy@gmail.com) * @date 2015年12月3日 * @since JDK 1.6 */ @Component -public class SubscribeMessageHandler extends - MessageHandlerAdapter { +public class SubscribeMessageHandler extends MessageHandlerAdapter { - @Override - public WeixinResponse doHandle0(WeixinRequest request, ScribeEventMessage message) - throws WeixinException { - return new TextResponse("欢迎关注~"); - } + @Override + public WeixinResponse doHandle0(WeixinRequest request, ScribeEventMessage message) { + return new TextResponse("欢迎关注~"); + } } diff --git a/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/TextMessageHandler.java b/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/TextMessageHandler.java index b3f1f16a..913857b1 100644 --- a/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/TextMessageHandler.java +++ b/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/TextMessageHandler.java @@ -11,7 +11,7 @@ import com.foxinmy.weixin4j.response.WeixinResponse; /** * 文本消息处理 - * + * * @className TextMessageHandler * @author jinyu(foxinmy@gmail.com) * @date 2015年11月18日 @@ -19,9 +19,8 @@ import com.foxinmy.weixin4j.response.WeixinResponse; */ @Component public class TextMessageHandler extends MessageHandlerAdapter { - @Override - public WeixinResponse doHandle0(WeixinRequest request, TextMessage message) - throws WeixinException { - return new TextResponse("收到了文本消息"); - } + @Override + public WeixinResponse doHandle0(WeixinRequest request, TextMessage message) { + return new TextResponse("收到了文本消息"); + } } diff --git a/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/VoiceMessageHandler.java b/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/VoiceMessageHandler.java index 9907ca99..8f2e6187 100644 --- a/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/VoiceMessageHandler.java +++ b/weixin4j-example/src/main/java/com/foxinmy/weixin4j/example/server/handler/VoiceMessageHandler.java @@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.example.server.handler; import org.springframework.stereotype.Component; -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.handler.MessageHandlerAdapter; import com.foxinmy.weixin4j.message.VoiceMessage; import com.foxinmy.weixin4j.request.WeixinRequest; @@ -11,7 +10,7 @@ import com.foxinmy.weixin4j.response.WeixinResponse; /** * 只处理语音消息 - * + * * @className VoiceMessageHandler * @author jinyu(foxinmy@gmail.com) * @date 2015年11月18日 @@ -20,12 +19,11 @@ import com.foxinmy.weixin4j.response.WeixinResponse; @Component public class VoiceMessageHandler extends MessageHandlerAdapter { - @Override - public WeixinResponse doHandle0(WeixinRequest request, VoiceMessage message) - throws WeixinException { - /** - * 返回一段文字给用户 - */ - return new TextResponse("你讲了一句话"); - } + @Override + public WeixinResponse doHandle0(WeixinRequest request, VoiceMessage message) { + /** + * 返回一段文字给用户 + */ + return new TextResponse("你讲了一句话"); + } } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/BeanFactory.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/BeanFactory.java index 53a2bf94..a6e08071 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/BeanFactory.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/dispatcher/BeanFactory.java @@ -2,11 +2,9 @@ package com.foxinmy.weixin4j.dispatcher; import java.util.Map; -import com.foxinmy.weixin4j.exception.WeixinException; - /** * Bean构造 - * + * * @className BeanFactory * @author jinyu(foxinmy@gmail.com) * @date 2015年5月7日 @@ -14,11 +12,11 @@ import com.foxinmy.weixin4j.exception.WeixinException; * @see */ public interface BeanFactory { - Object getBean(String name) throws WeixinException; + Object getBean(String name); - T getBean(Class clazz) throws WeixinException; + T getBean(Class clazz); - T getBean(String name, Class clazz) throws WeixinException; + T getBean(String name, Class clazz); - Map getBeans(Class clazz) throws WeixinException; + Map getBeans(Class clazz); } 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 d7ef25bb..cee8f804 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 @@ -1,19 +1,18 @@ package com.foxinmy.weixin4j.dispatcher; -import io.netty.channel.ChannelHandlerContext; -import io.netty.util.internal.logging.InternalLogger; -import io.netty.util.internal.logging.InternalLoggerFactory; - -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor; import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.response.WeixinResponse; +import io.netty.channel.ChannelHandlerContext; +import io.netty.util.internal.logging.InternalLogger; +import io.netty.util.internal.logging.InternalLoggerFactory; + /** * 微信消息的处理执行 - * + * * @className MessageHandlerExecutor * @author jinyu(foxinmy@gmail.com) * @date 2015年5月7日 @@ -55,7 +54,7 @@ public class MessageHandlerExecutor { /** * 执行预拦截动作 - * + * * @param request * 微信请求信息 * @param message @@ -63,8 +62,7 @@ public class MessageHandlerExecutor { * @return true则继续执行往下执行 * @throws WeixinException */ - public boolean applyPreHandle(WeixinRequest request, WeixinMessage message) - throws WeixinException { + public boolean applyPreHandle(WeixinRequest request, WeixinMessage message){ if (messageInterceptors != null) { for (int i = 0; i < messageInterceptors.length; i++) { WeixinMessageInterceptor interceptor = messageInterceptors[i]; @@ -81,7 +79,7 @@ public class MessageHandlerExecutor { /** * MessageHandler处理玩请求后的动作 - * + * * @param request * 微信请求 * @param response @@ -91,7 +89,7 @@ public class MessageHandlerExecutor { * @throws WeixinException */ public void applyPostHandle(WeixinRequest request, WeixinResponse response, - WeixinMessage message) throws WeixinException { + WeixinMessage message){ if (messageInterceptors == null) { return; } @@ -104,7 +102,7 @@ public class MessageHandlerExecutor { /** * 全部执行完毕后触发 - * + * * @param request * 微信请求 * @param response @@ -117,7 +115,7 @@ public class MessageHandlerExecutor { */ public void triggerAfterCompletion(WeixinRequest request, WeixinResponse response, WeixinMessage message, Exception exception) - throws WeixinException { + { if (messageInterceptors == null) { return; } @@ -126,7 +124,7 @@ public class MessageHandlerExecutor { try { interceptor.afterCompletion(context, request, response, message, messageHandler, exception); - } catch (WeixinException e) { + } catch (Exception e) { logger.error( "MessageInterceptor.afterCompletion threw exception", e); } 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 77a9791d..21f2bd23 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 @@ -1,12 +1,6 @@ package com.foxinmy.weixin4j.dispatcher; import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.DefaultFullHttpResponse; -import io.netty.handler.codec.http.FullHttpResponse; -import io.netty.util.internal.logging.InternalLogger; -import io.netty.util.internal.logging.InternalLoggerFactory; import java.io.ByteArrayInputStream; import java.lang.reflect.Constructor; @@ -26,7 +20,6 @@ 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.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor; import com.foxinmy.weixin4j.request.WeixinMessage; @@ -39,9 +32,16 @@ import com.foxinmy.weixin4j.util.HttpUtil; import com.foxinmy.weixin4j.util.ServerToolkits; import com.foxinmy.weixin4j.xml.MessageTransferHandler; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.util.internal.logging.InternalLogger; +import io.netty.util.internal.logging.InternalLoggerFactory; + /** * 微信消息分发器 - * + * * @className WeixinMessageDispatcher * @author jinyu(foxinmy@gmail.com) * @date 2015年5月7日 @@ -54,438 +54,372 @@ import com.foxinmy.weixin4j.xml.MessageTransferHandler; */ public class WeixinMessageDispatcher { - private final InternalLogger logger = InternalLoggerFactory - .getInstance(getClass()); + private final InternalLogger logger = InternalLoggerFactory.getInstance(getClass()); - /** - * 消息处理器 - */ - private List messageHandlerList; - private WeixinMessageHandler[] messageHandlers; - /** - * 消息处理器所在的包 - */ - private String[] messageHandlerPackages; + /** + * 消息处理器 + */ + private List messageHandlerList; + private WeixinMessageHandler[] messageHandlers; + /** + * 消息处理器所在的包 + */ + private String[] messageHandlerPackages; - /** - * 消息拦截器 - */ - private List messageInterceptorList; - private WeixinMessageInterceptor[] messageInterceptors; - /** - * 消息拦截器所在的包 - */ - private String[] messageInterceptorPackages; + /** + * 消息拦截器 + */ + private List messageInterceptorList; + private WeixinMessageInterceptor[] messageInterceptors; + /** + * 消息拦截器所在的包 + */ + private String[] messageInterceptorPackages; - /** - * Bean构造 - */ - private BeanFactory beanFactory; + /** + * Bean构造 + */ + private BeanFactory beanFactory; - /** - * 消息匹配 - */ - private WeixinMessageMatcher messageMatcher; - /** - * 消息转换 - */ - private Map, Unmarshaller> messageUnmarshaller; - /** - * 是否总是响应请求,如未匹配到MessageHandler时回复空白消息 - */ - private boolean alwaysResponse; + /** + * 消息匹配 + */ + private WeixinMessageMatcher messageMatcher; + /** + * 消息转换 + */ + private Map, Unmarshaller> messageUnmarshaller; + /** + * 是否总是响应请求,如未匹配到MessageHandler时回复空白消息 + */ + private boolean alwaysResponse; - public WeixinMessageDispatcher() { - this(new DefaultMessageMatcher()); - } + public WeixinMessageDispatcher() { + this(new DefaultMessageMatcher()); + } - public WeixinMessageDispatcher(WeixinMessageMatcher messageMatcher) { - this.messageMatcher = messageMatcher; - this.messageUnmarshaller = new ConcurrentHashMap, Unmarshaller>(); - } + public WeixinMessageDispatcher(WeixinMessageMatcher messageMatcher) { + this.messageMatcher = messageMatcher; + this.messageUnmarshaller = new ConcurrentHashMap, Unmarshaller>(); + } - /** - * 对消息进行一系列的处理,包括 拦截、匹配、分发等动作 - * - * @param context - * 上下文环境 - * @param request - * 微信请求 - * @param messageTransfer - * 微信消息 - * @throws WeixinException - */ - public void doDispatch(final ChannelHandlerContext context, - final WeixinRequest request) throws WeixinException { - WeixinMessageTransfer messageTransfer = MessageTransferHandler - .parser(request); - context.channel().attr(ServerToolkits.MESSAGE_TRANSFER_KEY) - .set(messageTransfer); - WeixinMessageKey messageKey = defineMessageKey(messageTransfer, request); - Class targetClass = messageMatcher - .match(messageKey); - WeixinMessage message = messageRead(request.getOriginalContent(), - targetClass); - logger.info("define '{}' matched '{}'", messageKey, targetClass); - MessageHandlerExecutor handlerExecutor = getHandlerExecutor(context, - request, messageKey, message, messageTransfer.getNodeNames()); - if (handlerExecutor == null - || handlerExecutor.getMessageHandler() == null) { - noHandlerFound(context, request, message); - return; - } - if (!handlerExecutor.applyPreHandle(request, message)) { - return; - } - Exception exception = null; - WeixinResponse response = null; - try { - response = handlerExecutor.getMessageHandler().doHandle(request, - message, messageTransfer.getNodeNames()); - handlerExecutor.applyPostHandle(request, response, message); - context.writeAndFlush(response); - } catch (Exception e) { - exception = e; - } - handlerExecutor.triggerAfterCompletion(request, response, message, - exception); - } + /** + * 对消息进行一系列的处理,包括 拦截、匹配、分发等动作 + * + * @param context + * 上下文环境 + * @param request + * 微信请求 + * @param messageTransfer + * 微信消息 @ + */ + public void doDispatch(final ChannelHandlerContext context, final WeixinRequest request) { + WeixinMessageTransfer messageTransfer = MessageTransferHandler.parser(request); + context.channel().attr(ServerToolkits.MESSAGE_TRANSFER_KEY).set(messageTransfer); + WeixinMessageKey messageKey = defineMessageKey(messageTransfer, request); + Class targetClass = messageMatcher.match(messageKey); + WeixinMessage message = messageRead(request.getOriginalContent(), targetClass); + logger.info("define '{}' matched '{}'", messageKey, targetClass); + MessageHandlerExecutor handlerExecutor = getHandlerExecutor(context, request, messageKey, message, + messageTransfer.getNodeNames()); + if (handlerExecutor == null || handlerExecutor.getMessageHandler() == null) { + noHandlerFound(context, request, message); + return; + } + if (!handlerExecutor.applyPreHandle(request, message)) { + return; + } + Exception exception = null; + WeixinResponse response = null; + try { + response = handlerExecutor.getMessageHandler().doHandle(request, message, messageTransfer.getNodeNames()); + handlerExecutor.applyPostHandle(request, response, message); + context.writeAndFlush(response); + } catch (Exception e) { + exception = e; + } + handlerExecutor.triggerAfterCompletion(request, response, message, exception); + } - /** - * 声明messagekey - * - * @param messageTransfer - * 基础消息 - * @param request - * 请求信息 - * @return - */ - protected WeixinMessageKey defineMessageKey( - WeixinMessageTransfer messageTransfer, WeixinRequest request) { - return new WeixinMessageKey(messageTransfer.getMsgType(), - messageTransfer.getEventType(), - messageTransfer.getAccountType()); - } + /** + * 声明messagekey + * + * @param messageTransfer + * 基础消息 + * @param request + * 请求信息 + * @return + */ + protected WeixinMessageKey defineMessageKey(WeixinMessageTransfer messageTransfer, WeixinRequest request) { + return new WeixinMessageKey(messageTransfer.getMsgType(), messageTransfer.getEventType(), + messageTransfer.getAccountType()); + } - /** - * 未匹配到handler时触发 - * - * @param context - * 上下文环境 - * @param request - * 微信请求 - * @param message - * 微信消息 - */ - protected void noHandlerFound(ChannelHandlerContext context, - WeixinRequest request, WeixinMessage message) { - logger.warn("no handler found for {}", request); - if (alwaysResponse) { - context.write(BlankResponse.global); - } else { - FullHttpResponse response = new DefaultFullHttpResponse( - request.getProtocolVersion(), NOT_FOUND); - HttpUtil.resolveHeaders(response); - context.writeAndFlush(response).addListener( - ChannelFutureListener.CLOSE); - } - } + /** + * 未匹配到handler时触发 + * + * @param context + * 上下文环境 + * @param request + * 微信请求 + * @param message + * 微信消息 + */ + protected void noHandlerFound(ChannelHandlerContext context, WeixinRequest request, WeixinMessage message) { + logger.warn("no handler found for {}", request); + if (alwaysResponse) { + context.write(BlankResponse.global); + } else { + FullHttpResponse response = new DefaultFullHttpResponse(request.getProtocolVersion(), NOT_FOUND); + HttpUtil.resolveHeaders(response); + context.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); + } + } - /** - * MessageHandlerExecutor - * - * @param context - * 上下文环境 - * @param request - * 微信请求 - * @param messageKey - * 消息的key - * @param message - * 微信消息 - * @param nodeNames - * 节点名称集合 - * @return MessageHandlerExecutor - * @see MessageHandlerExecutor - * @throws WeixinException - */ - protected MessageHandlerExecutor getHandlerExecutor( - ChannelHandlerContext context, WeixinRequest request, - WeixinMessageKey messageKey, WeixinMessage message, - Set nodeNames) throws WeixinException { - WeixinMessageHandler[] messageHandlers = getMessageHandlers(); - if (messageHandlers == null) { - return null; - } - logger.info("resolve message handlers '{}'", this.messageHandlerList); - List matchedMessageHandlers = new ArrayList(); - for (WeixinMessageHandler handler : messageHandlers) { - if (handler.canHandle(request, message, nodeNames)) { - matchedMessageHandlers.add(handler); - } - } - if (matchedMessageHandlers.isEmpty()) { - return null; - } - Collections.sort(matchedMessageHandlers, - new Comparator() { - @Override - public int compare(WeixinMessageHandler m1, - WeixinMessageHandler m2) { - return m2.weight() - m1.weight(); - } - }); - logger.info("matched message handlers '{}'", matchedMessageHandlers); - return new MessageHandlerExecutor(context, - matchedMessageHandlers.get(0), getMessageInterceptors()); - } + /** + * MessageHandlerExecutor + * + * @param context + * 上下文环境 + * @param request + * 微信请求 + * @param messageKey + * 消息的key + * @param message + * 微信消息 + * @param nodeNames + * 节点名称集合 + * @return MessageHandlerExecutor + * @see MessageHandlerExecutor @ + */ + protected MessageHandlerExecutor getHandlerExecutor(ChannelHandlerContext context, WeixinRequest request, + WeixinMessageKey messageKey, WeixinMessage message, Set nodeNames) { + WeixinMessageHandler[] messageHandlers = getMessageHandlers(); + if (messageHandlers == null) { + return null; + } + logger.info("resolve message handlers '{}'", this.messageHandlerList); + List matchedMessageHandlers = new ArrayList(); + for (WeixinMessageHandler handler : messageHandlers) { + if (handler.canHandle(request, message, nodeNames)) { + matchedMessageHandlers.add(handler); + } + } + if (matchedMessageHandlers.isEmpty()) { + return null; + } + Collections.sort(matchedMessageHandlers, new Comparator() { + @Override + public int compare(WeixinMessageHandler m1, WeixinMessageHandler m2) { + return m2.weight() - m1.weight(); + } + }); + logger.info("matched message handlers '{}'", matchedMessageHandlers); + return new MessageHandlerExecutor(context, matchedMessageHandlers.get(0), getMessageInterceptors()); + } - /** - * 获取所有的handler - * - * @return handler集合 - * @see com.foxinmy.weixin4j.handler.WeixinMessageHandler - * @throws WeixinException - */ - public WeixinMessageHandler[] getMessageHandlers() throws WeixinException { - if (this.messageHandlers == null) { - if (messageHandlerPackages != null) { - List> messageHandlerClass = new ArrayList>(); - for (String packageName : messageHandlerPackages) { - messageHandlerClass.addAll(ClassUtil - .getClasses(packageName)); - } - if (beanFactory != null) { - for (Class clazz : messageHandlerClass) { - if (clazz.isInterface() - || Modifier.isAbstract(clazz.getModifiers()) - || !WeixinMessageHandler.class - .isAssignableFrom(clazz)) { - continue; - } - try { - messageHandlerList - .add((WeixinMessageHandler) beanFactory - .getBean(clazz)); - } catch (RuntimeException ex) { // multiple - for (Object o : beanFactory.getBeans(clazz) - .values()) { - if (o.getClass() == clazz) { - messageHandlerList - .add((WeixinMessageHandler) o); - break; - } - } - } - } - } else { - for (Class clazz : messageHandlerClass) { - if (clazz.isInterface() - || Modifier.isAbstract(clazz.getModifiers()) - || !WeixinMessageHandler.class - .isAssignableFrom(clazz)) { - continue; - } - try { - Constructor ctor = clazz - .getDeclaredConstructor(); - ServerToolkits.makeConstructorAccessible(ctor); - messageHandlerList.add((WeixinMessageHandler) ctor - .newInstance((Object[]) null)); - } catch (Exception ex) { - throw new WeixinException(clazz.getName() - + " instantiate fail", ex); - } - } - } - } - if (messageHandlerList != null - && !this.messageHandlerList.isEmpty()) { - this.messageHandlers = this.messageHandlerList - .toArray(new WeixinMessageHandler[this.messageHandlerList - .size()]); - } - } - return this.messageHandlers; - } + /** + * 获取所有的handler + * + * @return handler集合 + * @see com.foxinmy.weixin4j.handler.WeixinMessageHandler @ + */ + public WeixinMessageHandler[] getMessageHandlers() { + if (this.messageHandlers == null) { + if (messageHandlerPackages != null) { + List> messageHandlerClass = new ArrayList>(); + for (String packageName : messageHandlerPackages) { + messageHandlerClass.addAll(ClassUtil.getClasses(packageName)); + } + if (beanFactory != null) { + for (Class clazz : messageHandlerClass) { + if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()) + || !WeixinMessageHandler.class.isAssignableFrom(clazz)) { + continue; + } + try { + messageHandlerList.add((WeixinMessageHandler) beanFactory.getBean(clazz)); + } catch (RuntimeException ex) { // multiple + for (Object o : beanFactory.getBeans(clazz).values()) { + if (o.getClass() == clazz) { + messageHandlerList.add((WeixinMessageHandler) o); + break; + } + } + } + } + } else { + for (Class clazz : messageHandlerClass) { + if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()) + || !WeixinMessageHandler.class.isAssignableFrom(clazz)) { + continue; + } + try { + Constructor ctor = clazz.getDeclaredConstructor(); + ServerToolkits.makeConstructorAccessible(ctor); + messageHandlerList.add((WeixinMessageHandler) ctor.newInstance((Object[]) null)); + } catch (Exception ex) { + throw new RuntimeException(clazz.getName() + " instantiate fail", ex); + } + } + } + } + if (messageHandlerList != null && !this.messageHandlerList.isEmpty()) { + this.messageHandlers = this.messageHandlerList + .toArray(new WeixinMessageHandler[this.messageHandlerList.size()]); + } + } + return this.messageHandlers; + } - /** - * 获取所有的interceptor - * - * @return interceptor集合 - * @throws WeixinException - * @see com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor - */ - public WeixinMessageInterceptor[] getMessageInterceptors() - throws WeixinException { - if (this.messageInterceptors == null) { - if (this.messageInterceptorPackages != null) { - List> messageInterceptorClass = new ArrayList>(); - for (String packageName : messageInterceptorPackages) { - messageInterceptorClass.addAll(ClassUtil - .getClasses(packageName)); - } - if (beanFactory != null) { - for (Class clazz : messageInterceptorClass) { - if (clazz.isInterface() - || Modifier.isAbstract(clazz.getModifiers()) - || !WeixinMessageInterceptor.class - .isAssignableFrom(clazz)) { - continue; - } - try { - messageInterceptorList - .add((WeixinMessageInterceptor) beanFactory - .getBean(clazz)); - } catch (RuntimeException ex) { // multiple - for (Object o : beanFactory.getBeans(clazz) - .values()) { - if (o.getClass() == clazz) { - messageInterceptorList - .add((WeixinMessageInterceptor) o); - break; - } - } - } - } - } else { - for (Class clazz : messageInterceptorClass) { - if (clazz.isInterface() - || Modifier.isAbstract(clazz.getModifiers()) - || !WeixinMessageInterceptor.class - .isAssignableFrom(clazz)) { - continue; - } - try { - Constructor ctor = clazz - .getDeclaredConstructor(); - ServerToolkits.makeConstructorAccessible(ctor); - messageInterceptorList - .add((WeixinMessageInterceptor) ctor - .newInstance((Object[]) null)); - } catch (Exception ex) { - throw new WeixinException(clazz.getName() - + " instantiate fail", ex); - } - } - } - } - if (this.messageInterceptorList != null - && !this.messageInterceptorList.isEmpty()) { - Collections.sort(messageInterceptorList, - new Comparator() { - @Override - public int compare(WeixinMessageInterceptor m1, - WeixinMessageInterceptor m2) { - return m2.weight() - m1.weight(); - } - }); - this.messageInterceptors = this.messageInterceptorList - .toArray(new WeixinMessageInterceptor[this.messageInterceptorList - .size()]); - } - } - logger.info("resolve message interceptors '{}'", - this.messageInterceptorList); - return this.messageInterceptors; - } + /** + * 获取所有的interceptor + * + * @return interceptor集合 + * @ @see com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor + */ + public WeixinMessageInterceptor[] getMessageInterceptors() { + if (this.messageInterceptors == null) { + if (this.messageInterceptorPackages != null) { + List> messageInterceptorClass = new ArrayList>(); + for (String packageName : messageInterceptorPackages) { + messageInterceptorClass.addAll(ClassUtil.getClasses(packageName)); + } + if (beanFactory != null) { + for (Class clazz : messageInterceptorClass) { + if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()) + || !WeixinMessageInterceptor.class.isAssignableFrom(clazz)) { + continue; + } + try { + messageInterceptorList.add((WeixinMessageInterceptor) beanFactory.getBean(clazz)); + } catch (RuntimeException ex) { // multiple + for (Object o : beanFactory.getBeans(clazz).values()) { + if (o.getClass() == clazz) { + messageInterceptorList.add((WeixinMessageInterceptor) o); + break; + } + } + } + } + } else { + for (Class clazz : messageInterceptorClass) { + if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()) + || !WeixinMessageInterceptor.class.isAssignableFrom(clazz)) { + continue; + } + try { + Constructor ctor = clazz.getDeclaredConstructor(); + ServerToolkits.makeConstructorAccessible(ctor); + messageInterceptorList.add((WeixinMessageInterceptor) ctor.newInstance((Object[]) null)); + } catch (Exception ex) { + throw new RuntimeException(clazz.getName() + " instantiate fail", ex); + } + } + } + } + if (this.messageInterceptorList != null && !this.messageInterceptorList.isEmpty()) { + Collections.sort(messageInterceptorList, new Comparator() { + @Override + public int compare(WeixinMessageInterceptor m1, WeixinMessageInterceptor m2) { + return m2.weight() - m1.weight(); + } + }); + this.messageInterceptors = this.messageInterceptorList + .toArray(new WeixinMessageInterceptor[this.messageInterceptorList.size()]); + } + } + logger.info("resolve message interceptors '{}'", this.messageInterceptorList); + return this.messageInterceptors; + } - /** - * jaxb读取微信消息 - * - * @param message - * xml消息 - * @param clazz - * 消息类型 - * @return 消息对象 - * @throws WeixinException - */ - protected M messageRead(String message, - Class clazz) throws WeixinException { - if (clazz == null) { - return null; - } - try { - Source source = new StreamSource(new ByteArrayInputStream( - ServerToolkits.getBytesUtf8(message))); - JAXBElement jaxbElement = getUnmarshaller(clazz).unmarshal( - source, clazz); - return jaxbElement.getValue(); - } catch (JAXBException e) { - throw new WeixinException(e); - } - } + /** + * jaxb读取微信消息 + * + * @param message + * xml消息 + * @param clazz + * 消息类型 + * @return 消息对象 @ + */ + protected M messageRead(String message, Class clazz) { + if (clazz == null) { + return null; + } + try { + Source source = new StreamSource(new ByteArrayInputStream(ServerToolkits.getBytesUtf8(message))); + JAXBElement jaxbElement = getUnmarshaller(clazz).unmarshal(source, clazz); + return jaxbElement.getValue(); + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } - /** - * xml消息转换器 - * - * @param clazz - * 消息类型 - * @return 消息转换器 - * @throws WeixinException - */ - 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; - } + /** + * xml消息转换器 + * + * @param clazz + * 消息类型 + * @return 消息转换器 @ + */ + protected Unmarshaller getUnmarshaller(Class clazz) { + 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 RuntimeException(e); + } + } + return unmarshaller; + } - public void setMessageHandlerList( - List messageHandlerList) { - this.messageHandlerList = messageHandlerList; - } + public void setMessageHandlerList(List messageHandlerList) { + this.messageHandlerList = messageHandlerList; + } - public void setMessageInterceptorList( - List messageInterceptorList) { - this.messageInterceptorList = messageInterceptorList; - } + public void setMessageInterceptorList(List messageInterceptorList) { + this.messageInterceptorList = messageInterceptorList; + } - public String[] getMessageHandlerPackages() { - return messageHandlerPackages; - } + public String[] getMessageHandlerPackages() { + return messageHandlerPackages; + } - public String[] getMessageInterceptorPackages() { - return messageInterceptorPackages; - } + public String[] getMessageInterceptorPackages() { + return messageInterceptorPackages; + } - public void setMessageHandlerPackages(String... messageHandlerPackages) { - this.messageHandlerPackages = messageHandlerPackages; - } + public void setMessageHandlerPackages(String... messageHandlerPackages) { + this.messageHandlerPackages = messageHandlerPackages; + } - public void setMessageInterceptorPackages( - String... messageInterceptorPackages) { - this.messageInterceptorPackages = messageInterceptorPackages; - } + public void setMessageInterceptorPackages(String... messageInterceptorPackages) { + this.messageInterceptorPackages = messageInterceptorPackages; + } - public BeanFactory getBeanFactory() { - return beanFactory; - } + public BeanFactory getBeanFactory() { + return beanFactory; + } - public void setBeanFactory(BeanFactory beanFactory) { - this.beanFactory = beanFactory; - } + public void setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } - public void registMessageClass(WeixinMessageKey messageKey, - Class messageClass) { - messageMatcher.regist(messageKey, messageClass); - } + public void registMessageClass(WeixinMessageKey messageKey, Class messageClass) { + messageMatcher.regist(messageKey, messageClass); + } - public WeixinMessageMatcher getMessageMatcher() { - return this.messageMatcher; - } + public WeixinMessageMatcher getMessageMatcher() { + return this.messageMatcher; + } - /** - * 打开总是响应开关,如未匹配到MessageHandler时回复空白消息 - */ - public void openAlwaysResponse() { - this.alwaysResponse = true; - } + /** + * 打开总是响应开关,如未匹配到MessageHandler时回复空白消息 + */ + public void openAlwaysResponse() { + this.alwaysResponse = true; + } } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/exception/WeixinException.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/exception/WeixinException.java deleted file mode 100644 index 26f659f2..00000000 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/exception/WeixinException.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.foxinmy.weixin4j.exception; - -/** - * 微信异常 - * - * @className WeixinException - * @author jinyu(foxinmy@gmail.com) - * @date 2014年4月10日 - * @since JDK 1.6 - * @see - */ -public class WeixinException extends Exception { - - private static final long serialVersionUID = 7148145661883468514L; - - private String errorCode; - private String errorMsg; - - public WeixinException(String errorCode, String errorMsg) { - this.errorCode = errorCode; - this.errorMsg = errorMsg; - } - - public WeixinException(String errorMsg) { - this.errorCode = "-1"; - this.errorMsg = errorMsg; - } - - public WeixinException(Exception e) { - super(e); - } - - public WeixinException(String errorMsg, Exception e) { - super(e); - this.errorMsg = errorMsg; - } - - public String getErrorCode() { - return errorCode; - } - - public String getErrorMsg() { - return errorMsg; - } - - @Override - public String getMessage() { - return this.errorCode + "," + this.errorMsg; - } -} 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 c3b5f59e..397e2a7c 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 @@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.handler; import java.util.Set; -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.response.TextResponse; @@ -10,7 +9,7 @@ import com.foxinmy.weixin4j.response.WeixinResponse; /** * 调试消息处理器 - * + * * @className DebugMessageHandler * @author jinyu(foxinmy@gmail.com) * @date 2015年5月17日 @@ -19,29 +18,27 @@ import com.foxinmy.weixin4j.response.WeixinResponse; */ public class DebugMessageHandler implements WeixinMessageHandler { - public static final DebugMessageHandler global = new DebugMessageHandler(); + public static final DebugMessageHandler global = new DebugMessageHandler(); - private DebugMessageHandler() { + private DebugMessageHandler() { - } + } - @Override - public boolean canHandle(WeixinRequest request, WeixinMessage message, - Set nodeNames) throws WeixinException { - return true; - } + @Override + public boolean canHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) { + return true; + } - @Override - public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, - Set nodeNames) throws WeixinException { - String content = message == null ? request.getOriginalContent() - .replaceAll("\\!\\[CDATA\\[", "").replaceAll("\\]\\]", "") - : message.toString(); - return new TextResponse(content); - } + @Override + public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) { + String content = message == null + ? request.getOriginalContent().replaceAll("\\!\\[CDATA\\[", "").replaceAll("\\]\\]", "") + : message.toString(); + return new TextResponse(content); + } - @Override - public int weight() { - return 0; - } + @Override + public int weight() { + return 0; + } } 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 8031e8ba..abbc7faa 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 @@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.handler; import java.util.Set; -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.response.WeixinResponse; @@ -10,7 +9,7 @@ import com.foxinmy.weixin4j.util.ClassUtil; /** * 消息适配器:对于特定的消息类型进行适配,如text文本、voice语音消息 - * + * * @className MessageHandlerAdapter * @author jinyu(foxinmy@gmail.com) * @date 2015年5月17日 @@ -18,56 +17,48 @@ import com.foxinmy.weixin4j.util.ClassUtil; * @see com.foxinmy.weixin4j.request.WeixinMessage */ @SuppressWarnings("unchecked") -public abstract class MessageHandlerAdapter implements - WeixinMessageHandler { +public abstract class MessageHandlerAdapter implements WeixinMessageHandler { - @Override - public boolean canHandle(WeixinRequest request, WeixinMessage message, - Set nodeNames) throws WeixinException { - return message != null - && message.getClass() == ClassUtil.getGenericType(getClass()) - && canHandle0(request, (M) message); - } + @Override + public boolean canHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) { + return message != null && message.getClass() == ClassUtil.getGenericType(getClass()) + && canHandle0(request, (M) message); + } - /** - * 能否处理请求 - * - * @param request - * 微信请求 - * @param message - * 微信消息 - * @return true则执行doHandler0 - * @throws WeixinException - */ - public boolean canHandle0(WeixinRequest request, M message) - throws WeixinException { - return true; - } + /** + * 能否处理请求 + * + * @param request + * 微信请求 + * @param message + * 微信消息 + * @return true则执行doHandler0 @ + */ + public boolean canHandle0(WeixinRequest request, M message) { + return true; + } - @Override - public WeixinResponse doHandle(WeixinRequest request, - WeixinMessage message, Set nodeNames) - throws WeixinException { - return doHandle0(request, (M) message); - } + @Override + public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) { + return doHandle0(request, (M) message); + } - /** - * 处理请求 - * - * @param request - * 微信请求 - * @param message - * 微信消息 - * @return - */ - public abstract WeixinResponse doHandle0(WeixinRequest request, M message) - throws WeixinException; + /** + * 处理请求 + * + * @param request + * 微信请求 + * @param message + * 微信消息 + * @return + */ + public abstract WeixinResponse doHandle0(WeixinRequest request, M message); - /** - * 缺省值为1,存在多个匹配到的MessageHandler则比较weight大小 - */ - @Override - public int weight() { - return 1; - } + /** + * 缺省值为1,存在多个匹配到的MessageHandler则比较weight大小 + */ + @Override + public int weight() { + return 1; + } } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/MultipleMessageHandlerAdapter.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/MultipleMessageHandlerAdapter.java index 00fb4c2e..1d18bf84 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/MultipleMessageHandlerAdapter.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/handler/MultipleMessageHandlerAdapter.java @@ -3,13 +3,12 @@ package com.foxinmy.weixin4j.handler; import java.util.HashSet; import java.util.Set; -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinRequest; /** * 多个消息类型适配 - * + * * @className MultipleMessageHandlerAdapter * @author jinyu(foxinmy@gmail.com) * @date 2016年3月12日 @@ -18,41 +17,40 @@ import com.foxinmy.weixin4j.request.WeixinRequest; */ public abstract class MultipleMessageHandlerAdapter implements WeixinMessageHandler { - private final Set> messageClasses; + private final Set> messageClasses; - public MultipleMessageHandlerAdapter(Class... messageClasses) { - if (messageClasses == null) { - throw new IllegalArgumentException("messageClasses not be empty"); - } - this.messageClasses = new HashSet>( - Math.max((int) (messageClasses.length / .75f) + 1, 16)); - for (Class clazz : messageClasses) { - this.messageClasses.add(clazz); - } - } + public MultipleMessageHandlerAdapter(Class... messageClasses) { + if (messageClasses == null) { + throw new IllegalArgumentException("messageClasses not be empty"); + } + this.messageClasses = new HashSet>( + Math.max((int) (messageClasses.length / .75f) + 1, 16)); + for (Class clazz : messageClasses) { + this.messageClasses.add(clazz); + } + } - @Override - public boolean canHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) - throws WeixinException { - return message != null && messageClasses.contains(message.getClass()) && canHandle0(request, message); - } + @Override + public boolean canHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) { + return message != null && messageClasses.contains(message.getClass()) && canHandle0(request, message); + } - /** - * 能否处理请求 - * - * @param request - * 微信请求 - * @param message - * 微信消息 - * @return true则执行doHandler - * @throws WeixinException - */ - public boolean canHandle0(WeixinRequest request, WeixinMessage message) throws WeixinException { - return true; - } + /** + * 能否处理请求 + * + * @param request + * 微信请求 + * @param message + * 微信消息 + * @return true则执行doHandler + * @throws WeixinException + */ + public boolean canHandle0(WeixinRequest request, WeixinMessage message) { + return true; + } - @Override - public int weight() { - return 1; - } + @Override + public int weight() { + return 1; + } } \ No newline at end of file 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 0075bc91..3c41f8f7 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 @@ -2,14 +2,13 @@ package com.foxinmy.weixin4j.handler; import java.util.Set; -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.response.WeixinResponse; /** * 微信消息处理器 - * + * * @className WeixinMessageHandler * @author jinyu(foxinmy@gmail.com) * @date 2015年5月7日 @@ -19,38 +18,36 @@ import com.foxinmy.weixin4j.response.WeixinResponse; */ public interface WeixinMessageHandler { - /** - * 能否处理请求 - * - * @param request - * 微信请求 - * @param message - * 微信消息 - * @param nodeNames - * 节点名称集合 - * @return true则执行doHandle - */ - public boolean canHandle(WeixinRequest request, WeixinMessage message, - Set nodeNames) throws WeixinException; + /** + * 能否处理请求 + * + * @param request + * 微信请求 + * @param message + * 微信消息 + * @param nodeNames + * 节点名称集合 + * @return true则执行doHandle + */ + public boolean canHandle(WeixinRequest request, WeixinMessage message, Set nodeNames); - /** - * 处理请求 - * - * @param request - * 微信请求 - * @param message - * 微信消息 - * @param nodeNames - * 节点名称集合 - * @return 回复内容 - */ - public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, - Set nodeNames) throws WeixinException; + /** + * 处理请求 + * + * @param request + * 微信请求 + * @param message + * 微信消息 + * @param nodeNames + * 节点名称集合 + * @return 回复内容 + */ + public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set nodeNames); - /** - * 用于匹配到多个MessageHandler时权重降序排列,数字越大优先级越高 - * - * @return 权重 - */ - public int weight(); + /** + * 用于匹配到多个MessageHandler时权重降序排列,数字越大优先级越高 + * + * @return 权重 + */ + public int weight(); } 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 16fa9cec..7701dcc8 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 @@ -1,47 +1,41 @@ package com.foxinmy.weixin4j.interceptor; -import io.netty.channel.ChannelHandlerContext; - -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.response.WeixinResponse; +import io.netty.channel.ChannelHandlerContext; + /** * 消息拦截适配 - * + * * @className MessageInterceptorAdapter * @author jinyu(foxinmy@gmail.com) * @date 2015年5月14日 * @since JDK 1.6 * @see */ -public abstract class MessageInterceptorAdapter implements - WeixinMessageInterceptor { +public abstract class MessageInterceptorAdapter implements WeixinMessageInterceptor { - @Override - public boolean preHandle(ChannelHandlerContext context, - WeixinRequest request, WeixinMessage message, WeixinMessageHandler handler) - throws WeixinException { - return true; - } + @Override + public boolean preHandle(ChannelHandlerContext context, WeixinRequest request, WeixinMessage message, + WeixinMessageHandler handler) { + return true; + } - @Override - public void postHandle(ChannelHandlerContext context, - WeixinRequest request, WeixinResponse response, WeixinMessage message, - WeixinMessageHandler handler) throws WeixinException { - } + @Override + public void postHandle(ChannelHandlerContext context, WeixinRequest request, WeixinResponse response, + WeixinMessage message, WeixinMessageHandler handler) { + } - @Override - public void afterCompletion(ChannelHandlerContext context, - WeixinRequest request, WeixinResponse response, WeixinMessage message, - WeixinMessageHandler handler, Exception exception) - throws WeixinException { - } + @Override + public void afterCompletion(ChannelHandlerContext context, WeixinRequest request, WeixinResponse response, + WeixinMessage message, WeixinMessageHandler handler, Exception exception) { + } - @Override - public int weight() { - return 0; - } + @Override + public int weight() { + return 0; + } } 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 599a8a88..04cd5c67 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 @@ -1,16 +1,15 @@ package com.foxinmy.weixin4j.interceptor; -import io.netty.channel.ChannelHandlerContext; - -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.response.WeixinResponse; +import io.netty.channel.ChannelHandlerContext; + /** * 微信消息拦截器 - * + * * @className WeixinMessageInterceptor * @author jinyu(foxinmy@gmail.com) * @date 2015年5月7日 @@ -21,7 +20,7 @@ public interface WeixinMessageInterceptor { /** * 执行handler前 - * + * * @param context * 通道环境 * @param request @@ -34,12 +33,11 @@ public interface WeixinMessageInterceptor { * @throws WeixinException */ boolean preHandle(ChannelHandlerContext context, WeixinRequest request, - WeixinMessage message, WeixinMessageHandler handler) - throws WeixinException; + WeixinMessage message, WeixinMessageHandler handler); /** * 执行handler后 - * + * * @param context * 通道环境 * @param request @@ -54,11 +52,11 @@ public interface WeixinMessageInterceptor { */ void postHandle(ChannelHandlerContext context, WeixinRequest request, WeixinResponse response, WeixinMessage message, - WeixinMessageHandler handler) throws WeixinException; + WeixinMessageHandler handler); /** * 全部执行后 - * + * * @param context * 通道环境 * @param request @@ -73,12 +71,11 @@ public interface WeixinMessageInterceptor { */ void afterCompletion(ChannelHandlerContext context, WeixinRequest request, WeixinResponse response, WeixinMessage message, - WeixinMessageHandler handler, Exception exception) - throws WeixinException; + WeixinMessageHandler handler, Exception exception); /** * 用于匹配到多个MessageHandler时权重降序排列,数字越大优先级越高 - * + * * @return 权重 */ int weight(); diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/SingleResponseEncoder.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/SingleResponseEncoder.java index dcaafa1b..c2014ff4 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/SingleResponseEncoder.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/SingleResponseEncoder.java @@ -1,21 +1,20 @@ package com.foxinmy.weixin4j.socket; +import java.util.List; + +import com.foxinmy.weixin4j.response.SingleResponse; +import com.foxinmy.weixin4j.util.HttpUtil; +import com.foxinmy.weixin4j.util.ServerToolkits; + import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; -import java.util.List; - -import com.foxinmy.weixin4j.exception.WeixinException; -import com.foxinmy.weixin4j.response.SingleResponse; -import com.foxinmy.weixin4j.util.HttpUtil; -import com.foxinmy.weixin4j.util.ServerToolkits; - /** * 单一回复编码类 - * + * * @className SingleResponseEncoder * @author jinyu(foxinmy@gmail.com) * @date 2015年08月02日 @@ -23,18 +22,14 @@ import com.foxinmy.weixin4j.util.ServerToolkits; * @see com.foxinmy.weixin4j.response.SingleResponse */ @ChannelHandler.Sharable -public class SingleResponseEncoder extends - MessageToMessageEncoder { +public class SingleResponseEncoder extends MessageToMessageEncoder { - private final InternalLogger logger = InternalLoggerFactory - .getInstance(getClass()); + private final InternalLogger logger = InternalLoggerFactory.getInstance(getClass()); - @Override - protected void encode(ChannelHandlerContext ctx, SingleResponse response, - List out) throws WeixinException { - String content = response.toContent(); - ctx.writeAndFlush(HttpUtil.createHttpResponse(content, - ServerToolkits.CONTENTTYPE$TEXT_PLAIN)); - logger.info("encode single response:{}", content); - } + @Override + protected void encode(ChannelHandlerContext ctx, SingleResponse response, List out) { + String content = response.toContent(); + ctx.writeAndFlush(HttpUtil.createHttpResponse(content, ServerToolkits.CONTENTTYPE$TEXT_PLAIN)); + logger.info("encode single response:{}", content); + } } \ No newline at end of file diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinMessageDecoder.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinMessageDecoder.java index 8d7a2e33..bc8ae5ca 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinMessageDecoder.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinMessageDecoder.java @@ -5,7 +5,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.type.EncryptType; import com.foxinmy.weixin4j.util.AesToken; @@ -50,7 +49,7 @@ public class WeixinMessageDecoder extends MessageToMessageDecoder out) throws WeixinException { + protected void decode(ChannelHandlerContext ctx, FullHttpRequest req, List out) { String messageContent = req.content().toString(ServerToolkits.UTF_8); QueryStringDecoder queryDecoder = new QueryStringDecoder(req.uri(), true); HttpMethod method = req.method(); @@ -68,7 +67,7 @@ public class WeixinMessageDecoder extends MessageToMessageDecoder { - private final InternalLogger logger = InternalLoggerFactory - .getInstance(getClass()); +public class WeixinRequestHandler extends SimpleChannelInboundHandler { + private final InternalLogger logger = InternalLoggerFactory.getInstance(getClass()); - private final WeixinMessageDispatcher messageDispatcher; + private final WeixinMessageDispatcher messageDispatcher; - public WeixinRequestHandler(WeixinMessageDispatcher messageDispatcher) { - this.messageDispatcher = messageDispatcher; - } + public WeixinRequestHandler(WeixinMessageDispatcher messageDispatcher) { + this.messageDispatcher = messageDispatcher; + } - public void channelReadComplete(ChannelHandlerContext ctx) { - ctx.flush(); - } + public void channelReadComplete(ChannelHandlerContext ctx) { + ctx.flush(); + } - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - ctx.close(); - logger.error(cause); - } + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + ctx.close(); + logger.error(cause); + } - @Override - protected void channelRead0(ChannelHandlerContext ctx, WeixinRequest request) - throws WeixinException { - AesToken aesToken = request.getAesToken(); - // 消息字段不完整返回400 - if (aesToken == null - || (ServerToolkits.isBlank(request.getSignature()) && ServerToolkits - .isBlank(request.getMsgSignature()))) { - ctx.writeAndFlush(resolveResponse(BAD_REQUEST, request)) - .addListener(ChannelFutureListener.CLOSE); - return; - } - /** - * 公众平台:无论Get,Post都带signature参数,当开启aes模式时带msg_signature参数 - * 企业号:无论Get,Post都带msg_signature参数 - * 一般来说:signature验证url上的参数签名,msg_signature验证消息体签名 - **/ - if (request.getMethod() == HttpMethod.GET) { - // URL参数签名验证 - if (!ServerToolkits.isBlank(request.getSignature()) - && MessageUtil.signature(aesToken.getToken(), - request.getTimeStamp(), request.getNonce()).equals( - request.getSignature())) { - ctx.writeAndFlush(new SingleResponse(request.getEchoStr())); - return; - } - // XML消息签名验证 - if (!ServerToolkits.isBlank(request.getMsgSignature()) - && MessageUtil.signature(aesToken.getToken(), - request.getTimeStamp(), request.getNonce(), - request.getEchoStr()).equals( - request.getMsgSignature())) { - ctx.writeAndFlush(new SingleResponse(MessageUtil.aesDecrypt( - null, aesToken.getAesKey(), request.getEchoStr()))); - return; - } - ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)).addListener( - ChannelFutureListener.CLOSE); - return; - } else if (request.getMethod() == HttpMethod.POST) { - // URL参数签名验证 - if (!ServerToolkits.isBlank(request.getSignature()) - && !MessageUtil.signature(aesToken.getToken(), - request.getTimeStamp(), request.getNonce()).equals( - request.getSignature())) { - ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)) - .addListener(ChannelFutureListener.CLOSE); - return; - } - // XML消息签名验证 - if (request.getEncryptType() == EncryptType.AES - && !MessageUtil.signature(aesToken.getToken(), - request.getTimeStamp(), request.getNonce(), - request.getEncryptContent()).equals( - request.getMsgSignature())) { - ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)) - .addListener(ChannelFutureListener.CLOSE); - return; - } - } else { - // 访问其它URL - ctx.writeAndFlush(resolveResponse(METHOD_NOT_ALLOWED, request)) - .addListener(ChannelFutureListener.CLOSE); - return; - } - messageDispatcher.doDispatch(ctx, request); - } + @Override + protected void channelRead0(ChannelHandlerContext ctx, WeixinRequest request) { + AesToken aesToken = request.getAesToken(); + // 消息字段不完整返回400 + if (aesToken == null || (ServerToolkits.isBlank(request.getSignature()) + && ServerToolkits.isBlank(request.getMsgSignature()))) { + ctx.writeAndFlush(resolveResponse(BAD_REQUEST, request)).addListener(ChannelFutureListener.CLOSE); + return; + } + /** + * 公众平台:无论Get,Post都带signature参数,当开启aes模式时带msg_signature参数 + * 企业号:无论Get,Post都带msg_signature参数 + * 一般来说:signature验证url上的参数签名,msg_signature验证消息体签名 + **/ + if (request.getMethod() == HttpMethod.GET) { + // URL参数签名验证 + if (!ServerToolkits.isBlank(request.getSignature()) + && MessageUtil.signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce()) + .equals(request.getSignature())) { + ctx.writeAndFlush(new SingleResponse(request.getEchoStr())); + return; + } + // XML消息签名验证 + if (!ServerToolkits.isBlank(request.getMsgSignature()) && MessageUtil + .signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce(), request.getEchoStr()) + .equals(request.getMsgSignature())) { + ctx.writeAndFlush( + new SingleResponse(MessageUtil.aesDecrypt(null, aesToken.getAesKey(), request.getEchoStr()))); + return; + } + ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)).addListener(ChannelFutureListener.CLOSE); + return; + } else if (request.getMethod() == HttpMethod.POST) { + // URL参数签名验证 + if (!ServerToolkits.isBlank(request.getSignature()) + && !MessageUtil.signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce()) + .equals(request.getSignature())) { + ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)).addListener(ChannelFutureListener.CLOSE); + return; + } + // XML消息签名验证 + if (request.getEncryptType() == EncryptType.AES + && !MessageUtil.signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce(), + request.getEncryptContent()).equals(request.getMsgSignature())) { + ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)).addListener(ChannelFutureListener.CLOSE); + return; + } + } else { + // 访问其它URL + ctx.writeAndFlush(resolveResponse(METHOD_NOT_ALLOWED, request)).addListener(ChannelFutureListener.CLOSE); + return; + } + messageDispatcher.doDispatch(ctx, request); + } - private FullHttpResponse resolveResponse(HttpResponseStatus responseStatus, - WeixinRequest request) { - FullHttpResponse response = new DefaultFullHttpResponse( - request.getProtocolVersion(), responseStatus); - HttpUtil.resolveHeaders(response); - return response; - } + private FullHttpResponse resolveResponse(HttpResponseStatus responseStatus, WeixinRequest request) { + FullHttpResponse response = new DefaultFullHttpResponse(request.getProtocolVersion(), responseStatus); + HttpUtil.resolveHeaders(response); + return response; + } } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinResponseEncoder.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinResponseEncoder.java index 1107b750..f40ebd04 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinResponseEncoder.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinResponseEncoder.java @@ -1,14 +1,7 @@ package com.foxinmy.weixin4j.socket; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToMessageEncoder; -import io.netty.util.internal.logging.InternalLogger; -import io.netty.util.internal.logging.InternalLoggerFactory; - import java.util.List; -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.type.EncryptType; import com.foxinmy.weixin4j.util.AesToken; @@ -16,6 +9,12 @@ import com.foxinmy.weixin4j.util.HttpUtil; import com.foxinmy.weixin4j.util.MessageUtil; import com.foxinmy.weixin4j.util.ServerToolkits; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageEncoder; +import io.netty.util.internal.logging.InternalLogger; +import io.netty.util.internal.logging.InternalLoggerFactory; + /** * 微信回复编码类 * @@ -23,66 +22,55 @@ import com.foxinmy.weixin4j.util.ServerToolkits; * @author jinyu(foxinmy@gmail.com) * @date 2014年11月13日 * @since JDK 1.6 - * @see 加密接入指引 + * @see 加密接入指引 * @see com.foxinmy.weixin4j.response.WeixinResponse */ @ChannelHandler.Sharable -public class WeixinResponseEncoder extends - MessageToMessageEncoder { +public class WeixinResponseEncoder extends MessageToMessageEncoder { - protected final InternalLogger logger = InternalLoggerFactory - .getInstance(getClass()); + protected final InternalLogger logger = InternalLoggerFactory.getInstance(getClass()); - private final String XML_START = ""; - // ---------------明文节点 - private final String ELEMENT_TOUSERNAME = ""; - private final String ELEMENT_FROMUSERNAME = ""; - private final String ELEMENT_CREATETIME = ""; - private final String ELEMENT_MSGTYPE = ""; - // ---------------密文节点 - private final String ELEMENT_MSGSIGNATURE = ""; - private final String ELEMENT_ENCRYPT = ""; - private final String ELEMENT_TIMESTAMP = ""; - private final String ELEMENT_NONCE = ""; - private final String XML_END = ""; + private final String XML_START = ""; + // ---------------明文节点 + private final String ELEMENT_TOUSERNAME = ""; + private final String ELEMENT_FROMUSERNAME = ""; + private final String ELEMENT_CREATETIME = ""; + private final String ELEMENT_MSGTYPE = ""; + // ---------------密文节点 + private final String ELEMENT_MSGSIGNATURE = ""; + private final String ELEMENT_ENCRYPT = ""; + private final String ELEMENT_TIMESTAMP = ""; + private final String ELEMENT_NONCE = ""; + private final String XML_END = ""; - @Override - protected void encode(ChannelHandlerContext ctx, WeixinResponse response, - List out) throws WeixinException { - WeixinMessageTransfer messageTransfer = ctx.channel() - .attr(ServerToolkits.MESSAGE_TRANSFER_KEY).get(); - EncryptType encryptType = messageTransfer.getEncryptType(); - StringBuilder content = new StringBuilder(); - content.append(XML_START); - content.append(String.format(ELEMENT_TOUSERNAME, - messageTransfer.getFromUserName())); - content.append(String.format(ELEMENT_FROMUSERNAME, - messageTransfer.getToUserName())); - content.append(String.format(ELEMENT_CREATETIME, - System.currentTimeMillis() / 1000l)); - content.append(String.format(ELEMENT_MSGTYPE, response.getMsgType())); - content.append(response.toContent()); - content.append(XML_END); - if (encryptType == EncryptType.AES) { - AesToken aesToken = messageTransfer.getAesToken(); - String nonce = ServerToolkits.generateRandomString(32); - String timestamp = Long - .toString(System.currentTimeMillis() / 1000l); - String encrtypt = MessageUtil.aesEncrypt(aesToken.getWeixinId(), - aesToken.getAesKey(), content.toString()); - String msgSignature = MessageUtil.signature(aesToken.getToken(), - nonce, timestamp, encrtypt); - content.delete(0, content.length()); - content.append(XML_START); - content.append(String.format(ELEMENT_NONCE, nonce)); - content.append(String.format(ELEMENT_TIMESTAMP, timestamp)); - content.append(String.format(ELEMENT_MSGSIGNATURE, msgSignature)); - content.append(String.format(ELEMENT_ENCRYPT, encrtypt)); - content.append(XML_END); - } - ctx.writeAndFlush(HttpUtil.createHttpResponse(content.toString(), - ServerToolkits.CONTENTTYPE$APPLICATION_XML)); - logger.info("{} encode weixin response:{}", encryptType, content); - } + @Override + protected void encode(ChannelHandlerContext ctx, WeixinResponse response, List out) { + WeixinMessageTransfer messageTransfer = ctx.channel().attr(ServerToolkits.MESSAGE_TRANSFER_KEY).get(); + EncryptType encryptType = messageTransfer.getEncryptType(); + StringBuilder content = new StringBuilder(); + content.append(XML_START); + content.append(String.format(ELEMENT_TOUSERNAME, messageTransfer.getFromUserName())); + content.append(String.format(ELEMENT_FROMUSERNAME, messageTransfer.getToUserName())); + content.append(String.format(ELEMENT_CREATETIME, System.currentTimeMillis() / 1000l)); + content.append(String.format(ELEMENT_MSGTYPE, response.getMsgType())); + content.append(response.toContent()); + content.append(XML_END); + if (encryptType == EncryptType.AES) { + AesToken aesToken = messageTransfer.getAesToken(); + String nonce = ServerToolkits.generateRandomString(32); + String timestamp = Long.toString(System.currentTimeMillis() / 1000l); + String encrtypt = MessageUtil.aesEncrypt(aesToken.getWeixinId(), aesToken.getAesKey(), content.toString()); + String msgSignature = MessageUtil.signature(aesToken.getToken(), nonce, timestamp, encrtypt); + content.delete(0, content.length()); + content.append(XML_START); + content.append(String.format(ELEMENT_NONCE, nonce)); + content.append(String.format(ELEMENT_TIMESTAMP, timestamp)); + content.append(String.format(ELEMENT_MSGSIGNATURE, msgSignature)); + content.append(String.format(ELEMENT_ENCRYPT, encrtypt)); + content.append(XML_END); + } + ctx.writeAndFlush(HttpUtil.createHttpResponse(content.toString(), ServerToolkits.CONTENTTYPE$APPLICATION_XML)); + logger.info("{} encode weixin response:{}", encryptType, content); + } } \ No newline at end of file diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/spring/SpringBeanFactory.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/spring/SpringBeanFactory.java index 91db893c..ffd67971 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/spring/SpringBeanFactory.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/spring/SpringBeanFactory.java @@ -5,11 +5,10 @@ import java.util.Map; import org.springframework.context.ApplicationContext; import com.foxinmy.weixin4j.dispatcher.BeanFactory; -import com.foxinmy.weixin4j.exception.WeixinException; /** * 使用spring容器获取bean - * + * * @className SpringBeanFactory * @author jinyu(foxinmy@gmail.com) * @date 2015年8月11日 @@ -18,29 +17,29 @@ import com.foxinmy.weixin4j.exception.WeixinException; */ public class SpringBeanFactory implements BeanFactory { - private ApplicationContext context; + private ApplicationContext context; - public SpringBeanFactory(ApplicationContext context) { - this.context = context; - } + public SpringBeanFactory(ApplicationContext context) { + this.context = context; + } - @Override - public Object getBean(String name) throws WeixinException { - return context.getBean(name); - } + @Override + public Object getBean(String name) { + return context.getBean(name); + } - @Override - public T getBean(Class classType) throws WeixinException { - return context.getBean(classType); - } + @Override + public T getBean(Class classType) { + return context.getBean(classType); + } - @Override - public T getBean(String name, Class classType) throws WeixinException { - return context.getBean(name, classType); - } + @Override + public T getBean(String name, Class classType) { + return context.getBean(name, classType); + } - @Override - public Map getBeans(Class clazz) throws WeixinException { - return context.getBeansOfType(clazz); - } + @Override + public Map getBeans(Class clazz) { + return context.getBeansOfType(clazz); + } } \ No newline at end of file diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java index 797c9d76..15410e81 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java @@ -11,7 +11,6 @@ import com.foxinmy.weixin4j.dispatcher.DefaultMessageMatcher; import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher; import com.foxinmy.weixin4j.dispatcher.WeixinMessageKey; import com.foxinmy.weixin4j.dispatcher.WeixinMessageMatcher; -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor; import com.foxinmy.weixin4j.request.WeixinMessage; @@ -173,7 +172,7 @@ public final class WeixinServerBootstrap { * 默认端口(30000)启动服务 * */ - public void startup() throws WeixinException { + public void startup() { startup(DEFAULT_SERVERPORT); } @@ -181,7 +180,7 @@ public final class WeixinServerBootstrap { * 指定端口启动服务 * */ - public void startup(int serverPort) throws WeixinException { + public void startup(int serverPort) { startup(DEFAULT_BOSSTHREADS, DEFAULT_WORKERTHREADS, serverPort); } @@ -197,7 +196,7 @@ public final class WeixinServerBootstrap { * @return * @throws WeixinException */ - public void startup(int bossThreads, int workerThreads, final int serverPort) throws WeixinException { + public void startup(int bossThreads, int workerThreads, final int serverPort) { messageDispatcher.setMessageHandlerList(messageHandlerList); messageDispatcher.setMessageInterceptorList(messageInterceptorList); try { @@ -218,7 +217,7 @@ public final class WeixinServerBootstrap { }).sync().channel(); ch.closeFuture().sync(); } catch (InterruptedException e) { - throw new WeixinException("netty server startup FAIL", e); + throw new RuntimeException(e); } finally { shutdown(); } 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 f0951ff1..c8046629 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 @@ -18,11 +18,9 @@ import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; -import com.foxinmy.weixin4j.exception.WeixinException; - /** * 对class的获取 - * + * * @className ClassUtil * @author jinyu(foxinmy@gmail.com) * @date 2014年10月31日 @@ -30,189 +28,180 @@ import com.foxinmy.weixin4j.exception.WeixinException; * @see */ public final class ClassUtil { - private final static String POINT = "."; - private final static String CLASS = ".class"; + private final static String POINT = "."; + private final static String CLASS = ".class"; - /** - * 获取某个包下所有的class信息 - * - * @param packageName - * 包名 - * @return - */ - public static List> getClasses(String packageName) - throws WeixinException { - String packageFileName = packageName.replace(POINT, File.separator); - URL fullPath = getDefaultClassLoader().getResource(packageFileName); - String protocol = fullPath.getProtocol(); - if (protocol.equals(ServerToolkits.PROTOCOL_FILE)) { - try { - File dir = new File(fullPath.toURI()); - return findClassesByFile(dir, packageName); - } catch (URISyntaxException e) { - throw new WeixinException(e); - } - } else if (protocol.equals(ServerToolkits.PROTOCOL_JAR)) { - try { - return findClassesByJar( - ((JarURLConnection) fullPath.openConnection()) - .getJarFile(), - packageName); - } catch (IOException e) { - throw new WeixinException(e); - } - } - return null; - } + /** + * 获取某个包下所有的class信息 + * + * @param packageName + * 包名 + * @return + */ + public static List> getClasses(String packageName) { + String packageFileName = packageName.replace(POINT, File.separator); + URL fullPath = getDefaultClassLoader().getResource(packageFileName); + String protocol = fullPath.getProtocol(); + if (protocol.equals(ServerToolkits.PROTOCOL_FILE)) { + try { + File dir = new File(fullPath.toURI()); + return findClassesByFile(dir, packageName); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } else if (protocol.equals(ServerToolkits.PROTOCOL_JAR)) { + try { + return findClassesByJar(((JarURLConnection) fullPath.openConnection()).getJarFile(), packageName); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return null; + } - /** - * 扫描目录下所有的class对象 - * - * @param dir - * 文件目录 - * @param packageName - * 包的全限类名 - * @return - */ - private static List> findClassesByFile(File dir, String packageName) { - List> classes = new ArrayList>(); - File[] files = dir.listFiles(new FilenameFilter() { - @Override - public boolean accept(File file, String name) { - return file.isDirectory() || file.getName().endsWith(CLASS); - } - }); - if (files != null) { - for (File file : files) { - if (file.isDirectory()) { - classes.addAll(findClassesByFile(file, packageName + POINT - + file.getName())); - } else { - try { - classes.add(Class.forName(packageName + POINT - + file.getName().replace(CLASS, ""))); - } catch (ClassNotFoundException e) { - ; - } - } - } - } - return classes; - } + /** + * 扫描目录下所有的class对象 + * + * @param dir + * 文件目录 + * @param packageName + * 包的全限类名 + * @return + */ + private static List> findClassesByFile(File dir, String packageName) { + List> classes = new ArrayList>(); + File[] files = dir.listFiles(new FilenameFilter() { + @Override + public boolean accept(File file, String name) { + return file.isDirectory() || file.getName().endsWith(CLASS); + } + }); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + classes.addAll(findClassesByFile(file, packageName + POINT + file.getName())); + } else { + try { + classes.add(Class.forName(packageName + POINT + file.getName().replace(CLASS, ""))); + } catch (ClassNotFoundException e) { + ; + } + } + } + } + return classes; + } - /** - * 扫描jar包下所有的class对象 - * - * @param jar - * jar包对象 - * @param packageName - * 包的全限类名 - * @return - */ - private static List> findClassesByJar(JarFile jar, - String packageName) { - List> classes = new ArrayList>(); - Enumeration jarEntries = jar.entries(); - while (jarEntries.hasMoreElements()) { - JarEntry jarEntry = jarEntries.nextElement(); - if (jarEntry.isDirectory()) { - continue; - } - String className = jarEntry.getName() - .replace(File.separator, POINT); - if (!className.startsWith(packageName) - || !className.endsWith(CLASS)) { - continue; - } - try { - classes.add(Class.forName(className.replace(CLASS, ""))); - } catch (ClassNotFoundException e) { - ; - } - } - return classes; - } + /** + * 扫描jar包下所有的class对象 + * + * @param jar + * jar包对象 + * @param packageName + * 包的全限类名 + * @return + */ + private static List> findClassesByJar(JarFile jar, String packageName) { + List> classes = new ArrayList>(); + Enumeration jarEntries = jar.entries(); + while (jarEntries.hasMoreElements()) { + JarEntry jarEntry = jarEntries.nextElement(); + if (jarEntry.isDirectory()) { + continue; + } + String className = jarEntry.getName().replace(File.separator, POINT); + if (!className.startsWith(packageName) || !className.endsWith(CLASS)) { + continue; + } + try { + classes.add(Class.forName(className.replace(CLASS, ""))); + } catch (ClassNotFoundException e) { + ; + } + } + return classes; + } - public static Object deepClone(Object obj) throws WeixinException { - ByteArrayOutputStream bos = null; - ObjectOutputStream oos = null; - ByteArrayInputStream bis = null; - ObjectInputStream ois = null; - try { - bos = new ByteArrayOutputStream(); - oos = new ObjectOutputStream(bos); - oos.writeObject(obj); - bis = new ByteArrayInputStream(bos.toByteArray()); - ois = new ObjectInputStream(bis); - return ois.readObject(); - } catch (IOException e) { - throw new WeixinException(e); - } catch (ClassNotFoundException e) { - throw new WeixinException(e); - } finally { - try { - if (bos != null) { - bos.close(); - } - if (oos != null) { - oos.close(); - } - if (bis != null) { - bis.close(); - } - if (ois != null) { - ois.close(); - } - } catch (IOException e) { - ;// ignore - } - } - } + public static Object deepClone(Object obj) { + ByteArrayOutputStream bos = null; + ObjectOutputStream oos = null; + ByteArrayInputStream bis = null; + ObjectInputStream ois = null; + try { + bos = new ByteArrayOutputStream(); + oos = new ObjectOutputStream(bos); + oos.writeObject(obj); + bis = new ByteArrayInputStream(bos.toByteArray()); + ois = new ObjectInputStream(bis); + return ois.readObject(); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } finally { + try { + if (bos != null) { + bos.close(); + } + if (oos != null) { + oos.close(); + } + if (bis != null) { + bis.close(); + } + if (ois != null) { + ois.close(); + } + } catch (IOException e) { + ;// ignore + } + } + } - /** - * 获得泛型类型 - * - * @param object - * @return - */ - public static Class getGenericType(Class clazz) { - if(clazz == Object.class){ - return null; - } - Type type = clazz.getGenericSuperclass(); - if (type instanceof ParameterizedType) { - ParameterizedType ptype = ((ParameterizedType) type); - Type[] args = ptype.getActualTypeArguments(); - return (Class) args[0]; - } - return getGenericType(clazz.getSuperclass()); - } + /** + * 获得泛型类型 + * + * @param object + * @return + */ + public static Class getGenericType(Class clazz) { + if (clazz == Object.class) { + return null; + } + Type type = clazz.getGenericSuperclass(); + if (type instanceof ParameterizedType) { + ParameterizedType ptype = ((ParameterizedType) type); + Type[] args = ptype.getActualTypeArguments(); + return (Class) args[0]; + } + return getGenericType(clazz.getSuperclass()); + } - public static ClassLoader getDefaultClassLoader() { - ClassLoader cl = null; - try { - cl = Thread.currentThread().getContextClassLoader(); - } catch (Throwable ex) { - // Cannot access thread context ClassLoader - falling back... - } - if (cl == null) { - // No thread context class loader -> use class loader of this class. - cl = ClassUtil.class.getClassLoader(); - if (cl == null) { - // getClassLoader() returning null indicates the bootstrap - // ClassLoader - try { - cl = ClassLoader.getSystemClassLoader(); - } catch (Throwable ex) { - // Cannot access system ClassLoader - oh well, maybe the - // caller can live with null... - } - } - } - return cl; - } + public static ClassLoader getDefaultClassLoader() { + ClassLoader cl = null; + try { + cl = Thread.currentThread().getContextClassLoader(); + } catch (Throwable ex) { + // Cannot access thread context ClassLoader - falling back... + } + if (cl == null) { + // No thread context class loader -> use class loader of this class. + cl = ClassUtil.class.getClassLoader(); + if (cl == null) { + // getClassLoader() returning null indicates the bootstrap + // ClassLoader + try { + cl = ClassLoader.getSystemClassLoader(); + } catch (Throwable ex) { + // Cannot access system ClassLoader - oh well, maybe the + // caller can live with null... + } + } + } + return cl; + } - public static void main(String[] args) throws WeixinException { - System.err.println(getClasses("com.foxinmy.weixin4j.qy.event")); - } + public static void main(String[] args) { + System.err.println(getClasses("com.foxinmy.weixin4j.qy.event")); + } } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/MessageUtil.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/MessageUtil.java index 8801d2aa..fca1cf1a 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/MessageUtil.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/MessageUtil.java @@ -7,11 +7,10 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import com.foxinmy.weixin4j.base64.Base64; -import com.foxinmy.weixin4j.exception.WeixinException; /** * 消息工具类 - * + * * @className MessageUtil * @author jinyu(foxinmy@gmail.com) * @date 2014年10月31日 @@ -19,150 +18,137 @@ import com.foxinmy.weixin4j.exception.WeixinException; * @see */ public final class MessageUtil { - /** - * 验证微信签名 - * - * @param signature - * 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数 - * @return 开发者通过检验signature对请求进行相关校验。若确认此次GET请求来自微信服务器 - * 请原样返回echostr参数内容,则接入生效 成为开发者成功,否则接入失败 - * @see 接入指南 - */ - public static String signature(String... para) { - Arrays.sort(para); - StringBuffer sb = new StringBuffer(); - for (String str : para) { - sb.append(str); - } - return ServerToolkits.digestSHA1(sb.toString()); - } + /** + * 验证微信签名 + * + * @param signature + * 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数 + * @return 开发者通过检验signature对请求进行相关校验。若确认此次GET请求来自微信服务器 + * 请原样返回echostr参数内容,则接入生效 成为开发者成功,否则接入失败 + * @see 接入指南 + */ + public static String signature(String... para) { + Arrays.sort(para); + StringBuffer sb = new StringBuffer(); + for (String str : para) { + sb.append(str); + } + return ServerToolkits.digestSHA1(sb.toString()); + } - /** - * 对xml消息加密 - * - * @param appId - * 应用ID - * @param encodingAesKey - * 加密密钥 - * @param xmlContent - * 原始消息体 - * @return aes加密后的消息体 - * @throws WeixinException - */ - public static String aesEncrypt(String appId, String encodingAesKey, - String xmlContent) throws WeixinException { - /** - * 其中,msg_encrypt=Base64_Encode(AES_Encrypt [random(16B)+ msg_len(4B) + - * msg + $AppId]) - * - * random(16B)为16字节的随机字符串;msg_len为msg长度,占4个字节(网络字节序),$AppId为公众账号的AppId - */ - byte[] randomBytes = ServerToolkits.getBytesUtf8(ServerToolkits - .generateRandomString(16)); - byte[] xmlBytes = ServerToolkits.getBytesUtf8(xmlContent); - int xmlLength = xmlBytes.length; - byte[] orderBytes = new byte[4]; - orderBytes[3] = (byte) (xmlLength & 0xFF); - orderBytes[2] = (byte) (xmlLength >> 8 & 0xFF); - orderBytes[1] = (byte) (xmlLength >> 16 & 0xFF); - orderBytes[0] = (byte) (xmlLength >> 24 & 0xFF); - byte[] appidBytes = ServerToolkits.getBytesUtf8(appId); + /** + * 对xml消息加密 + * + * @param appId + * 应用ID + * @param encodingAesKey + * 加密密钥 + * @param xmlContent + * 原始消息体 + * @return aes加密后的消息体 + * @throws WeixinException + */ + public static String aesEncrypt(String appId, String encodingAesKey, String xmlContent) { + /** + * 其中,msg_encrypt=Base64_Encode(AES_Encrypt [random(16B)+ msg_len(4B) + + * msg + $AppId]) + * + * random(16B)为16字节的随机字符串;msg_len为msg长度,占4个字节(网络字节序),$AppId为公众账号的AppId + */ + byte[] randomBytes = ServerToolkits.getBytesUtf8(ServerToolkits.generateRandomString(16)); + byte[] xmlBytes = ServerToolkits.getBytesUtf8(xmlContent); + int xmlLength = xmlBytes.length; + byte[] orderBytes = new byte[4]; + orderBytes[3] = (byte) (xmlLength & 0xFF); + orderBytes[2] = (byte) (xmlLength >> 8 & 0xFF); + orderBytes[1] = (byte) (xmlLength >> 16 & 0xFF); + orderBytes[0] = (byte) (xmlLength >> 24 & 0xFF); + byte[] appidBytes = ServerToolkits.getBytesUtf8(appId); - int byteLength = randomBytes.length + xmlLength + orderBytes.length - + appidBytes.length; - // ... + pad: 使用自定义的填充方式对明文进行补位填充 - byte[] padBytes = PKCS7Encoder.encode(byteLength); - // random + endian + xml + appid + pad 获得最终的字节流 - byte[] unencrypted = new byte[byteLength + padBytes.length]; - byteLength = 0; - // src:源数组;srcPos:源数组要复制的起始位置;dest:目的数组;destPos:目的数组放置的起始位置;length:复制的长度 - System.arraycopy(randomBytes, 0, unencrypted, byteLength, - randomBytes.length); - byteLength += randomBytes.length; - System.arraycopy(orderBytes, 0, unencrypted, byteLength, - orderBytes.length); - byteLength += orderBytes.length; - System.arraycopy(xmlBytes, 0, unencrypted, byteLength, xmlBytes.length); - byteLength += xmlBytes.length; - System.arraycopy(appidBytes, 0, unencrypted, byteLength, - appidBytes.length); - byteLength += appidBytes.length; - System.arraycopy(padBytes, 0, unencrypted, byteLength, padBytes.length); - try { - byte[] aesKey = Base64.decodeBase64(encodingAesKey + "="); - // 设置加密模式为AES的CBC模式 - Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); - SecretKeySpec keySpec = new SecretKeySpec(aesKey, ServerToolkits.AES); - IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16); - cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv); - // 加密 - byte[] encrypted = cipher.doFinal(unencrypted); - // 使用BASE64对加密后的字符串进行编码 - // return Base64.encodeBase64String(encrypted); - return Base64 - .encodeBase64String(encrypted); - } catch (Exception e) { - throw new WeixinException("-40006", "AES加密失败:" + e.getMessage()); - } - } + int byteLength = randomBytes.length + xmlLength + orderBytes.length + appidBytes.length; + // ... + pad: 使用自定义的填充方式对明文进行补位填充 + byte[] padBytes = PKCS7Encoder.encode(byteLength); + // random + endian + xml + appid + pad 获得最终的字节流 + byte[] unencrypted = new byte[byteLength + padBytes.length]; + byteLength = 0; + // src:源数组;srcPos:源数组要复制的起始位置;dest:目的数组;destPos:目的数组放置的起始位置;length:复制的长度 + System.arraycopy(randomBytes, 0, unencrypted, byteLength, randomBytes.length); + byteLength += randomBytes.length; + System.arraycopy(orderBytes, 0, unencrypted, byteLength, orderBytes.length); + byteLength += orderBytes.length; + System.arraycopy(xmlBytes, 0, unencrypted, byteLength, xmlBytes.length); + byteLength += xmlBytes.length; + System.arraycopy(appidBytes, 0, unencrypted, byteLength, appidBytes.length); + byteLength += appidBytes.length; + System.arraycopy(padBytes, 0, unencrypted, byteLength, padBytes.length); + try { + byte[] aesKey = Base64.decodeBase64(encodingAesKey + "="); + // 设置加密模式为AES的CBC模式 + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + SecretKeySpec keySpec = new SecretKeySpec(aesKey, ServerToolkits.AES); + IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16); + cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv); + // 加密 + byte[] encrypted = cipher.doFinal(unencrypted); + // 使用BASE64对加密后的字符串进行编码 + // return Base64.encodeBase64String(encrypted); + return Base64.encodeBase64String(encrypted); + } catch (Exception e) { + throw new RuntimeException("-40006,AES加密失败:" + e.getMessage()); + } + } - /** - * 对AES消息解密 - * - * @param appId - * @param encodingAesKey - * aes加密的密钥 - * @param encryptContent - * 加密的消息体 - * @return 解密后的字符 - * @throws WeixinException - */ - public static String aesDecrypt(String appId, String encodingAesKey, - String encryptContent) throws WeixinException { - byte[] aesKey = Base64.decodeBase64(encodingAesKey + "="); - byte[] original; - try { - // 设置解密模式为AES的CBC模式 - Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); - SecretKeySpec key_spec = new SecretKeySpec(aesKey, ServerToolkits.AES); - IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, - 0, 16)); - cipher.init(Cipher.DECRYPT_MODE, key_spec, iv); - // 使用BASE64对密文进行解码 - byte[] encrypted = Base64.decodeBase64(encryptContent); - // 解密 - original = cipher.doFinal(encrypted); - } catch (Exception e) { - throw new WeixinException("-40007", "AES解密失败:" + e.getMessage()); - } - String xmlContent, fromAppId; - try { - // 去除补位字符 - byte[] bytes = PKCS7Encoder.decode(original); - /** - * AES加密的buf由16个字节的随机字符串、4个字节的msg_len(网络字节序)、msg和$AppId组成, - * 其中msg_len为msg的长度,$AppId为公众帐号的AppId - */ - // 获取表示xml长度的字节数组 - byte[] lengthByte = Arrays.copyOfRange(bytes, 16, 20); - // 获取xml消息主体的长度(byte[]2int) - // http://my.oschina.net/u/169390/blog/97495 - int xmlLength = lengthByte[3] & 0xff | (lengthByte[2] & 0xff) << 8 - | (lengthByte[1] & 0xff) << 16 - | (lengthByte[0] & 0xff) << 24; - xmlContent = ServerToolkits.newStringUtf8(Arrays.copyOfRange(bytes, 20, - 20 + xmlLength)); - fromAppId = ServerToolkits.newStringUtf8(Arrays.copyOfRange(bytes, - 20 + xmlLength, bytes.length)); - } catch (Exception e) { - throw new WeixinException("-40008", "xml内容不合法:" + e.getMessage()); - } - // 校验appId是否一致 - if (appId != null && !fromAppId.trim().equals(appId)) { - throw new WeixinException("-40005", "校验AppID失败,expect " + appId - + ",but actual is " + fromAppId); - } - return xmlContent; - } + /** + * 对AES消息解密 + * + * @param appId + * @param encodingAesKey + * aes加密的密钥 + * @param encryptContent + * 加密的消息体 + * @return 解密后的字符 + * @throws WeixinException + */ + public static String aesDecrypt(String appId, String encodingAesKey, String encryptContent) { + byte[] aesKey = Base64.decodeBase64(encodingAesKey + "="); + byte[] original; + try { + // 设置解密模式为AES的CBC模式 + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + SecretKeySpec key_spec = new SecretKeySpec(aesKey, ServerToolkits.AES); + IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16)); + cipher.init(Cipher.DECRYPT_MODE, key_spec, iv); + // 使用BASE64对密文进行解码 + byte[] encrypted = Base64.decodeBase64(encryptContent); + // 解密 + original = cipher.doFinal(encrypted); + } catch (Exception e) { + throw new RuntimeException("-40007,AES解密失败:" + e.getMessage()); + } + String xmlContent, fromAppId; + try { + // 去除补位字符 + byte[] bytes = PKCS7Encoder.decode(original); + /** + * AES加密的buf由16个字节的随机字符串、4个字节的msg_len(网络字节序)、msg和$AppId组成, + * 其中msg_len为msg的长度,$AppId为公众帐号的AppId + */ + // 获取表示xml长度的字节数组 + byte[] lengthByte = Arrays.copyOfRange(bytes, 16, 20); + // 获取xml消息主体的长度(byte[]2int) + // http://my.oschina.net/u/169390/blog/97495 + int xmlLength = lengthByte[3] & 0xff | (lengthByte[2] & 0xff) << 8 | (lengthByte[1] & 0xff) << 16 + | (lengthByte[0] & 0xff) << 24; + xmlContent = ServerToolkits.newStringUtf8(Arrays.copyOfRange(bytes, 20, 20 + xmlLength)); + fromAppId = ServerToolkits.newStringUtf8(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length)); + } catch (Exception e) { + throw new RuntimeException("-40008,xml内容不合法:" + e.getMessage()); + } + // 校验appId是否一致 + if (appId != null && !fromAppId.trim().equals(appId)) { + throw new RuntimeException("-40005,校验AppID失败,expect " + appId + ",but actual is " + fromAppId); + } + return xmlContent; + } } diff --git a/weixin4j-server/src/test/java/com/foxinmy/weixin4j/server/ext/SuiteMessageHandler.java b/weixin4j-server/src/test/java/com/foxinmy/weixin4j/server/ext/SuiteMessageHandler.java index d9e9f30a..0bb5bdd9 100644 --- a/weixin4j-server/src/test/java/com/foxinmy/weixin4j/server/ext/SuiteMessageHandler.java +++ b/weixin4j-server/src/test/java/com/foxinmy/weixin4j/server/ext/SuiteMessageHandler.java @@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.server.ext; import java.util.Set; -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.qy.suite.SuiteEventType; import com.foxinmy.weixin4j.qy.suite.SuiteMessage; @@ -13,7 +12,7 @@ import com.foxinmy.weixin4j.response.WeixinResponse; /** * 企业号套件消息处理 - * + * * @className SuiteMessageHandler * @author jy * @date 2015年6月25日 @@ -21,29 +20,27 @@ import com.foxinmy.weixin4j.response.WeixinResponse; */ public class SuiteMessageHandler implements WeixinMessageHandler { - @Override - public boolean canHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) - throws WeixinException { - return nodeNames.contains("suiteid"); - } + @Override + public boolean canHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) { + return nodeNames.contains("suiteid"); + } - @Override - public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) - throws WeixinException { - SuiteMessage suiteMessage = null; // 转换为 SuiteMessage - SuiteEventType eventType = suiteMessage.getFormatEventType(); - if (eventType == SuiteEventType.suite_ticket) { - // do something - } else if (eventType == SuiteEventType.change_auth) { - // do something - } else if (eventType == SuiteEventType.cancel_auth) { - // do something - } - return BlankResponse.global; - } + @Override + public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) { + SuiteMessage suiteMessage = null; // 转换为 SuiteMessage + SuiteEventType eventType = suiteMessage.getFormatEventType(); + if (eventType == SuiteEventType.suite_ticket) { + // do something + } else if (eventType == SuiteEventType.change_auth) { + // do something + } else if (eventType == SuiteEventType.cancel_auth) { + // do something + } + return BlankResponse.global; + } - @Override - public int weight() { - return 0; - } + @Override + public int weight() { + return 0; + } } 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 2327e53f..4a20aece 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 @@ -1,13 +1,10 @@ package com.foxinmy.weixin4j.server.test; -import io.netty.channel.ChannelHandlerContext; - import java.util.Set; import org.springframework.context.ApplicationContext; import com.foxinmy.weixin4j.dispatcher.BeanFactory; -import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.handler.DebugMessageHandler; import com.foxinmy.weixin4j.handler.MessageHandlerAdapter; import com.foxinmy.weixin4j.handler.MultipleMessageHandlerAdapter; @@ -23,6 +20,8 @@ import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.spring.SpringBeanFactory; import com.foxinmy.weixin4j.startup.WeixinServerBootstrap; +import io.netty.channel.ChannelHandlerContext; + /** * 服务启动测试类 * @@ -34,139 +33,123 @@ import com.foxinmy.weixin4j.startup.WeixinServerBootstrap; */ public class MessageServerStartup { - // 公众号ID - final String weixinId = "wx4ab8f8de58159a57"; - // 开发者token - final String token = "weixin4j"; - // AES密钥(安全模式) - final String aesKey = ""; + // 公众号ID + final String weixinId = "wx4ab8f8de58159a57"; + // 开发者token + final String token = "weixin4j"; + // AES密钥(安全模式) + final String aesKey = ""; - /** - * 调试输出用户发来的消息 - * - * @throws WeixinException - */ - public void test1() throws WeixinException { - // 明文模式 - new WeixinServerBootstrap(token).addHandler(DebugMessageHandler.global) - .startup(); - // 密文模式 - // new WeixinServerBootstrap(weixinId, token, aesKey).addHandler( - // DebugMessageHandler.global).startup(); - } + /** + * 调试输出用户发来的消息 + * + */ + public void test1() { + // 明文模式 + new WeixinServerBootstrap(token).addHandler(DebugMessageHandler.global).startup(); + // 密文模式 + // new WeixinServerBootstrap(weixinId, token, aesKey).addHandler( + // DebugMessageHandler.global).startup(); + } - /** - * 针对特定消息类型 - * - * @throws WeixinException - */ - public void test2() throws WeixinException { - // 针对文本消息回复 - WeixinMessageHandler textMessageHandler = new MessageHandlerAdapter() { - @Override - public WeixinResponse doHandle0(WeixinRequest request, - TextMessage message) throws WeixinException { - return new TextResponse("HelloWorld!"); - } - }; - // 针对语音消息回复 - WeixinMessageHandler voiceMessageHandler = new MessageHandlerAdapter() { - @Override - public WeixinResponse doHandle0(WeixinRequest request, - VoiceMessage message) throws WeixinException { - return new TextResponse("HelloWorld!"); - } - }; - // 当消息类型为文本(text)或者语音时回复「HelloWorld」, 否则回复调试消息 - new WeixinServerBootstrap(weixinId, token, aesKey).addHandler( - textMessageHandler, voiceMessageHandler, - DebugMessageHandler.global).startup(); - } + /** + * 针对特定消息类型 + * + */ + public void test2() { + // 针对文本消息回复 + WeixinMessageHandler textMessageHandler = new MessageHandlerAdapter() { + @Override + public WeixinResponse doHandle0(WeixinRequest request, TextMessage message) { + return new TextResponse("HelloWorld!"); + } + }; + // 针对语音消息回复 + WeixinMessageHandler voiceMessageHandler = new MessageHandlerAdapter() { + @Override + public WeixinResponse doHandle0(WeixinRequest request, VoiceMessage message) { + return new TextResponse("HelloWorld!"); + } + }; + // 当消息类型为文本(text)或者语音时回复「HelloWorld」, 否则回复调试消息 + new WeixinServerBootstrap(weixinId, token, aesKey) + .addHandler(textMessageHandler, voiceMessageHandler, DebugMessageHandler.global).startup(); + } - /** - * 多种消息类型处理 - * - * @throws WeixinException - */ - public void test3() throws WeixinException { - @SuppressWarnings("unchecked") - MultipleMessageHandlerAdapter messageHandler = new MultipleMessageHandlerAdapter( - ScanEventMessage.class, TextMessage.class) { - @Override - public WeixinResponse doHandle(WeixinRequest request, - WeixinMessage message, Set nodeNames) - throws WeixinException { - return new TextResponse("处理了扫描和文字消息"); - } - }; - new WeixinServerBootstrap(token).addHandler(messageHandler, - DebugMessageHandler.global).startup(); - } + /** + * 多种消息类型处理 + * + */ + public void test3() { + @SuppressWarnings("unchecked") + MultipleMessageHandlerAdapter messageHandler = new MultipleMessageHandlerAdapter(ScanEventMessage.class, + TextMessage.class) { + @Override + public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set nodeNames) { + return new TextResponse("处理了扫描和文字消息"); + } + }; + new WeixinServerBootstrap(token).addHandler(messageHandler, DebugMessageHandler.global).startup(); + } - /** - * 扫描包添加handler - * - * @throws WeixinException - */ - public void test4() throws WeixinException { - // handler处理所在的包名(子包也会扫描) - String packageToScan = "com.foxinmy.weixin4j.handler"; - // handler默认使用 Class.newInstance - // 方式实例化,如果handler中含有service等类需要注入,可以声明一个BeanFactory,如SpringBeanFactory - ApplicationContext applicationContext = null; // spring容器 - BeanFactory beanFactory = new SpringBeanFactory(applicationContext); - new WeixinServerBootstrap(token).handlerPackagesToScan(packageToScan) - .openAlwaysResponse().resolveBeanFactory(beanFactory).startup(); - } + /** + * 扫描包添加handler + * + * @ + */ + public void test4() { + // handler处理所在的包名(子包也会扫描) + String packageToScan = "com.foxinmy.weixin4j.handler"; + // handler默认使用 Class.newInstance + // 方式实例化,如果handler中含有service等类需要注入,可以声明一个BeanFactory,如SpringBeanFactory + ApplicationContext applicationContext = null; // spring容器 + BeanFactory beanFactory = new SpringBeanFactory(applicationContext); + new WeixinServerBootstrap(token).handlerPackagesToScan(packageToScan).openAlwaysResponse() + .resolveBeanFactory(beanFactory).startup(); + } - /** - * 拦截器应用 - * - * @throws WeixinException - */ - public void test5() throws WeixinException { - // 拦截所有请求 - WeixinMessageInterceptor interceptor = new WeixinMessageInterceptor() { - @Override - public boolean preHandle(ChannelHandlerContext context, - WeixinRequest request, WeixinMessage message, - WeixinMessageHandler handler) throws WeixinException { - context.writeAndFlush(new TextResponse("所有消息被拦截了!")); - return false; - } + /** + * 拦截器应用 + * + * @ + */ + public void test5() { + // 拦截所有请求 + WeixinMessageInterceptor interceptor = new WeixinMessageInterceptor() { + @Override + public boolean preHandle(ChannelHandlerContext context, WeixinRequest request, WeixinMessage message, + WeixinMessageHandler handler) { + context.writeAndFlush(new TextResponse("所有消息被拦截了!")); + return false; + } - @Override - public void postHandle(ChannelHandlerContext context, - WeixinRequest request, WeixinResponse response, - WeixinMessage message, WeixinMessageHandler handler) - throws WeixinException { - System.err.println("preHandle返回为true,执行handler后"); - } + @Override + public void postHandle(ChannelHandlerContext context, WeixinRequest request, WeixinResponse response, + WeixinMessage message, WeixinMessageHandler handler) { + System.err.println("preHandle返回为true,执行handler后"); + } - @Override - public void afterCompletion(ChannelHandlerContext context, - WeixinRequest request, WeixinResponse response, - WeixinMessage message, WeixinMessageHandler handler, - Exception exception) throws WeixinException { - System.err.println("请求处理完毕"); - } + @Override + public void afterCompletion(ChannelHandlerContext context, WeixinRequest request, WeixinResponse response, + WeixinMessage message, WeixinMessageHandler handler, Exception exception) { + System.err.println("请求处理完毕"); + } - @Override - public int weight() { - return 0; - } - }; - new WeixinServerBootstrap(token).addInterceptor(interceptor) - .openAlwaysResponse().startup(); - } + @Override + public int weight() { + return 0; + } + }; + new WeixinServerBootstrap(token).addInterceptor(interceptor).openAlwaysResponse().startup(); + } - /** - * main方法入口 - * - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception { - new MessageServerStartup().test1(); - } + /** + * main方法入口 + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + new MessageServerStartup().test1(); + } }