removed WeixinException class

This commit is contained in:
jinyu 2017-06-23 18:26:25 +08:00
parent 4c0f96fcfe
commit 3c92d75276
27 changed files with 1210 additions and 1457 deletions

View File

@ -66,16 +66,12 @@ public class Weixin4jServerStartupWithThread implements ApplicationContextAware
new Thread(new Runnable() { new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
try {
bootstrap = new WeixinServerBootstrap(aesToken) // 指定开发者token信息 bootstrap = new WeixinServerBootstrap(aesToken) // 指定开发者token信息
.handlerPackagesToScan(handlerPackage) // 扫描处理消息的包 .handlerPackagesToScan(handlerPackage) // 扫描处理消息的包
.resolveBeanFactory(new SpringBeanFactory(applicationContext)) // 声明处理消息类由Spring容器去实例化 .resolveBeanFactory(new SpringBeanFactory(applicationContext)) // 声明处理消息类由Spring容器去实例化
.addHandler(DebugMessageHandler.global) // 当没有匹配到消息处理时输出调试信息开发环境打开 .addHandler(DebugMessageHandler.global) // 当没有匹配到消息处理时输出调试信息开发环境打开
.openAlwaysResponse(); // 当没有匹配到消息处理时输出空白回复(公众号不会出现该公众号无法提供服务的提示)正式环境打开 .openAlwaysResponse(); // 当没有匹配到消息处理时输出空白回复(公众号不会出现该公众号无法提供服务的提示)正式环境打开
bootstrap.startup(port); // 绑定服务的端口号即对外暴露(微信服务器URL地址)的服务端口 bootstrap.startup(port); // 绑定服务的端口号即对外暴露(微信服务器URL地址)的服务端口
} catch (WeixinException e) {
InternalLoggerFactory.getInstance(getClass()).error("weixin4j server startup:FAIL", e);
}
} }
}).start(); }).start();
} }

View File

@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.example.server.handler;
import java.util.Set; import java.util.Set;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.handler.WeixinMessageHandler;
import com.foxinmy.weixin4j.qy.chat.WeixinChatMessage; import com.foxinmy.weixin4j.qy.chat.WeixinChatMessage;
import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinMessage;
@ -13,15 +12,12 @@ import com.foxinmy.weixin4j.response.WeixinResponse;
public class ChatMessageHandler implements WeixinMessageHandler { public class ChatMessageHandler implements WeixinMessageHandler {
@Override @Override
public boolean canHandle(WeixinRequest request, WeixinMessage message, public boolean canHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) {
Set<String> nodeNames) throws WeixinException {
return nodeNames.contains("PackageId"); return nodeNames.contains("PackageId");
} }
@Override @Override
public WeixinResponse doHandle(WeixinRequest request, public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) {
WeixinMessage message, Set<String> nodeNames)
throws WeixinException {
WeixinChatMessage chatMessage = null; // 转换为实体 WeixinChatMessage chatMessage = null; // 转换为实体
return BlankResponse.global; return BlankResponse.global;
} }

View File

@ -11,6 +11,7 @@ import com.foxinmy.weixin4j.response.WeixinResponse;
/** /**
* 自定义处理消息 * 自定义处理消息
*
* @className CustomMessageHandler * @className CustomMessageHandler
* @author jinyu(foxinmy@gmail.com) * @author jinyu(foxinmy@gmail.com)
* @date 2017年1月19日 * @date 2017年1月19日
@ -20,16 +21,13 @@ import com.foxinmy.weixin4j.response.WeixinResponse;
public class CustomMessageHandler implements WeixinMessageHandler { public class CustomMessageHandler implements WeixinMessageHandler {
@Override @Override
public boolean canHandle(WeixinRequest request, WeixinMessage message, public boolean canHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) {
Set<String> nodeNames) throws WeixinException {
// 消息来源某个用户 // 消息来源某个用户
return message.getFromUserName().equals("xxx"); return message.getFromUserName().equals("xxx");
} }
@Override @Override
public WeixinResponse doHandle(WeixinRequest request, public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) {
WeixinMessage message, Set<String> nodeNames)
throws WeixinException {
return new TextResponse("是你,是你,还是你。"); return new TextResponse("是你,是你,还是你。");
} }

View File

@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.example.server.handler;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.message.TextMessage; import com.foxinmy.weixin4j.message.TextMessage;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
import com.foxinmy.weixin4j.response.TextResponse; import com.foxinmy.weixin4j.response.TextResponse;
@ -20,8 +19,7 @@ import com.foxinmy.weixin4j.response.WeixinResponse;
public class HelloMessageHandler extends TextMessageHandler { public class HelloMessageHandler extends TextMessageHandler {
@Override @Override
public boolean canHandle0(WeixinRequest request, TextMessage message) public boolean canHandle0(WeixinRequest request, TextMessage message) {
throws WeixinException {
/** /**
* 用户输入hello时 * 用户输入hello时
*/ */
@ -29,8 +27,7 @@ public class HelloMessageHandler extends TextMessageHandler {
} }
@Override @Override
public WeixinResponse doHandle0(WeixinRequest request, TextMessage message) public WeixinResponse doHandle0(WeixinRequest request, TextMessage message) {
throws WeixinException {
/** /**
* 返回用户world文本 * 返回用户world文本
*/ */

View File

@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.example.server.handler;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.handler.MessageHandlerAdapter; import com.foxinmy.weixin4j.handler.MessageHandlerAdapter;
import com.foxinmy.weixin4j.mp.event.ScribeEventMessage; import com.foxinmy.weixin4j.mp.event.ScribeEventMessage;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
@ -18,12 +17,10 @@ import com.foxinmy.weixin4j.response.WeixinResponse;
* @since JDK 1.6 * @since JDK 1.6
*/ */
@Component @Component
public class SubscribeMessageHandler extends public class SubscribeMessageHandler extends MessageHandlerAdapter<ScribeEventMessage> {
MessageHandlerAdapter<ScribeEventMessage> {
@Override @Override
public WeixinResponse doHandle0(WeixinRequest request, ScribeEventMessage message) public WeixinResponse doHandle0(WeixinRequest request, ScribeEventMessage message) {
throws WeixinException {
return new TextResponse("欢迎关注~"); return new TextResponse("欢迎关注~");
} }
} }

View File

@ -20,8 +20,7 @@ import com.foxinmy.weixin4j.response.WeixinResponse;
@Component @Component
public class TextMessageHandler extends MessageHandlerAdapter<TextMessage> { public class TextMessageHandler extends MessageHandlerAdapter<TextMessage> {
@Override @Override
public WeixinResponse doHandle0(WeixinRequest request, TextMessage message) public WeixinResponse doHandle0(WeixinRequest request, TextMessage message) {
throws WeixinException {
return new TextResponse("收到了文本消息"); return new TextResponse("收到了文本消息");
} }
} }

View File

@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.example.server.handler;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.handler.MessageHandlerAdapter; import com.foxinmy.weixin4j.handler.MessageHandlerAdapter;
import com.foxinmy.weixin4j.message.VoiceMessage; import com.foxinmy.weixin4j.message.VoiceMessage;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
@ -21,8 +20,7 @@ import com.foxinmy.weixin4j.response.WeixinResponse;
public class VoiceMessageHandler extends MessageHandlerAdapter<VoiceMessage> { public class VoiceMessageHandler extends MessageHandlerAdapter<VoiceMessage> {
@Override @Override
public WeixinResponse doHandle0(WeixinRequest request, VoiceMessage message) public WeixinResponse doHandle0(WeixinRequest request, VoiceMessage message) {
throws WeixinException {
/** /**
* 返回一段文字给用户 * 返回一段文字给用户
*/ */

View File

@ -2,8 +2,6 @@ package com.foxinmy.weixin4j.dispatcher;
import java.util.Map; import java.util.Map;
import com.foxinmy.weixin4j.exception.WeixinException;
/** /**
* Bean构造 * Bean构造
* *
@ -14,11 +12,11 @@ import com.foxinmy.weixin4j.exception.WeixinException;
* @see * @see
*/ */
public interface BeanFactory { public interface BeanFactory {
Object getBean(String name) throws WeixinException; Object getBean(String name);
<T> T getBean(Class<T> clazz) throws WeixinException; <T> T getBean(Class<T> clazz);
<T> T getBean(String name, Class<T> clazz) throws WeixinException; <T> T getBean(String name, Class<T> clazz);
<T> Map<String, T> getBeans(Class<T> clazz) throws WeixinException; <T> Map<String, T> getBeans(Class<T> clazz);
} }

View File

@ -1,16 +1,15 @@
package com.foxinmy.weixin4j.dispatcher; 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.handler.WeixinMessageHandler;
import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor; import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor;
import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinMessage;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.response.WeixinResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
/** /**
* 微信消息的处理执行 * 微信消息的处理执行
* *
@ -63,8 +62,7 @@ public class MessageHandlerExecutor {
* @return true则继续执行往下执行 * @return true则继续执行往下执行
* @throws WeixinException * @throws WeixinException
*/ */
public boolean applyPreHandle(WeixinRequest request, WeixinMessage message) public boolean applyPreHandle(WeixinRequest request, WeixinMessage message){
throws WeixinException {
if (messageInterceptors != null) { if (messageInterceptors != null) {
for (int i = 0; i < messageInterceptors.length; i++) { for (int i = 0; i < messageInterceptors.length; i++) {
WeixinMessageInterceptor interceptor = messageInterceptors[i]; WeixinMessageInterceptor interceptor = messageInterceptors[i];
@ -91,7 +89,7 @@ public class MessageHandlerExecutor {
* @throws WeixinException * @throws WeixinException
*/ */
public void applyPostHandle(WeixinRequest request, WeixinResponse response, public void applyPostHandle(WeixinRequest request, WeixinResponse response,
WeixinMessage message) throws WeixinException { WeixinMessage message){
if (messageInterceptors == null) { if (messageInterceptors == null) {
return; return;
} }
@ -117,7 +115,7 @@ public class MessageHandlerExecutor {
*/ */
public void triggerAfterCompletion(WeixinRequest request, public void triggerAfterCompletion(WeixinRequest request,
WeixinResponse response, WeixinMessage message, Exception exception) WeixinResponse response, WeixinMessage message, Exception exception)
throws WeixinException { {
if (messageInterceptors == null) { if (messageInterceptors == null) {
return; return;
} }
@ -126,7 +124,7 @@ public class MessageHandlerExecutor {
try { try {
interceptor.afterCompletion(context, request, response, interceptor.afterCompletion(context, request, response,
message, messageHandler, exception); message, messageHandler, exception);
} catch (WeixinException e) { } catch (Exception e) {
logger.error( logger.error(
"MessageInterceptor.afterCompletion threw exception", e); "MessageInterceptor.afterCompletion threw exception", e);
} }

View File

@ -1,12 +1,6 @@
package com.foxinmy.weixin4j.dispatcher; package com.foxinmy.weixin4j.dispatcher;
import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; 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.io.ByteArrayInputStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -26,7 +20,6 @@ import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source; import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource; import javax.xml.transform.stream.StreamSource;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.handler.WeixinMessageHandler;
import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor; import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor;
import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinMessage;
@ -39,6 +32,13 @@ import com.foxinmy.weixin4j.util.HttpUtil;
import com.foxinmy.weixin4j.util.ServerToolkits; import com.foxinmy.weixin4j.util.ServerToolkits;
import com.foxinmy.weixin4j.xml.MessageTransferHandler; 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;
/** /**
* 微信消息分发器 * 微信消息分发器
* *
@ -54,8 +54,7 @@ import com.foxinmy.weixin4j.xml.MessageTransferHandler;
*/ */
public class WeixinMessageDispatcher { public class WeixinMessageDispatcher {
private final InternalLogger logger = InternalLoggerFactory private final InternalLogger logger = InternalLoggerFactory.getInstance(getClass());
.getInstance(getClass());
/** /**
* 消息处理器 * 消息处理器
@ -112,25 +111,18 @@ public class WeixinMessageDispatcher {
* @param request * @param request
* 微信请求 * 微信请求
* @param messageTransfer * @param messageTransfer
* 微信消息 * 微信消息 @
* @throws WeixinException
*/ */
public void doDispatch(final ChannelHandlerContext context, public void doDispatch(final ChannelHandlerContext context, final WeixinRequest request) {
final WeixinRequest request) throws WeixinException { WeixinMessageTransfer messageTransfer = MessageTransferHandler.parser(request);
WeixinMessageTransfer messageTransfer = MessageTransferHandler context.channel().attr(ServerToolkits.MESSAGE_TRANSFER_KEY).set(messageTransfer);
.parser(request);
context.channel().attr(ServerToolkits.MESSAGE_TRANSFER_KEY)
.set(messageTransfer);
WeixinMessageKey messageKey = defineMessageKey(messageTransfer, request); WeixinMessageKey messageKey = defineMessageKey(messageTransfer, request);
Class<? extends WeixinMessage> targetClass = messageMatcher Class<? extends WeixinMessage> targetClass = messageMatcher.match(messageKey);
.match(messageKey); WeixinMessage message = messageRead(request.getOriginalContent(), targetClass);
WeixinMessage message = messageRead(request.getOriginalContent(),
targetClass);
logger.info("define '{}' matched '{}'", messageKey, targetClass); logger.info("define '{}' matched '{}'", messageKey, targetClass);
MessageHandlerExecutor handlerExecutor = getHandlerExecutor(context, MessageHandlerExecutor handlerExecutor = getHandlerExecutor(context, request, messageKey, message,
request, messageKey, message, messageTransfer.getNodeNames()); messageTransfer.getNodeNames());
if (handlerExecutor == null if (handlerExecutor == null || handlerExecutor.getMessageHandler() == null) {
|| handlerExecutor.getMessageHandler() == null) {
noHandlerFound(context, request, message); noHandlerFound(context, request, message);
return; return;
} }
@ -140,15 +132,13 @@ public class WeixinMessageDispatcher {
Exception exception = null; Exception exception = null;
WeixinResponse response = null; WeixinResponse response = null;
try { try {
response = handlerExecutor.getMessageHandler().doHandle(request, response = handlerExecutor.getMessageHandler().doHandle(request, message, messageTransfer.getNodeNames());
message, messageTransfer.getNodeNames());
handlerExecutor.applyPostHandle(request, response, message); handlerExecutor.applyPostHandle(request, response, message);
context.writeAndFlush(response); context.writeAndFlush(response);
} catch (Exception e) { } catch (Exception e) {
exception = e; exception = e;
} }
handlerExecutor.triggerAfterCompletion(request, response, message, handlerExecutor.triggerAfterCompletion(request, response, message, exception);
exception);
} }
/** /**
@ -160,10 +150,8 @@ public class WeixinMessageDispatcher {
* 请求信息 * 请求信息
* @return * @return
*/ */
protected WeixinMessageKey defineMessageKey( protected WeixinMessageKey defineMessageKey(WeixinMessageTransfer messageTransfer, WeixinRequest request) {
WeixinMessageTransfer messageTransfer, WeixinRequest request) { return new WeixinMessageKey(messageTransfer.getMsgType(), messageTransfer.getEventType(),
return new WeixinMessageKey(messageTransfer.getMsgType(),
messageTransfer.getEventType(),
messageTransfer.getAccountType()); messageTransfer.getAccountType());
} }
@ -177,17 +165,14 @@ public class WeixinMessageDispatcher {
* @param message * @param message
* 微信消息 * 微信消息
*/ */
protected void noHandlerFound(ChannelHandlerContext context, protected void noHandlerFound(ChannelHandlerContext context, WeixinRequest request, WeixinMessage message) {
WeixinRequest request, WeixinMessage message) {
logger.warn("no handler found for {}", request); logger.warn("no handler found for {}", request);
if (alwaysResponse) { if (alwaysResponse) {
context.write(BlankResponse.global); context.write(BlankResponse.global);
} else { } else {
FullHttpResponse response = new DefaultFullHttpResponse( FullHttpResponse response = new DefaultFullHttpResponse(request.getProtocolVersion(), NOT_FOUND);
request.getProtocolVersion(), NOT_FOUND);
HttpUtil.resolveHeaders(response); HttpUtil.resolveHeaders(response);
context.writeAndFlush(response).addListener( context.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
ChannelFutureListener.CLOSE);
} }
} }
@ -205,13 +190,10 @@ public class WeixinMessageDispatcher {
* @param nodeNames * @param nodeNames
* 节点名称集合 * 节点名称集合
* @return MessageHandlerExecutor * @return MessageHandlerExecutor
* @see MessageHandlerExecutor * @see MessageHandlerExecutor @
* @throws WeixinException
*/ */
protected MessageHandlerExecutor getHandlerExecutor( protected MessageHandlerExecutor getHandlerExecutor(ChannelHandlerContext context, WeixinRequest request,
ChannelHandlerContext context, WeixinRequest request, WeixinMessageKey messageKey, WeixinMessage message, Set<String> nodeNames) {
WeixinMessageKey messageKey, WeixinMessage message,
Set<String> nodeNames) throws WeixinException {
WeixinMessageHandler[] messageHandlers = getMessageHandlers(); WeixinMessageHandler[] messageHandlers = getMessageHandlers();
if (messageHandlers == null) { if (messageHandlers == null) {
return null; return null;
@ -226,52 +208,41 @@ public class WeixinMessageDispatcher {
if (matchedMessageHandlers.isEmpty()) { if (matchedMessageHandlers.isEmpty()) {
return null; return null;
} }
Collections.sort(matchedMessageHandlers, Collections.sort(matchedMessageHandlers, new Comparator<WeixinMessageHandler>() {
new Comparator<WeixinMessageHandler>() {
@Override @Override
public int compare(WeixinMessageHandler m1, public int compare(WeixinMessageHandler m1, WeixinMessageHandler m2) {
WeixinMessageHandler m2) {
return m2.weight() - m1.weight(); return m2.weight() - m1.weight();
} }
}); });
logger.info("matched message handlers '{}'", matchedMessageHandlers); logger.info("matched message handlers '{}'", matchedMessageHandlers);
return new MessageHandlerExecutor(context, return new MessageHandlerExecutor(context, matchedMessageHandlers.get(0), getMessageInterceptors());
matchedMessageHandlers.get(0), getMessageInterceptors());
} }
/** /**
* 获取所有的handler * 获取所有的handler
* *
* @return handler集合 * @return handler集合
* @see com.foxinmy.weixin4j.handler.WeixinMessageHandler * @see com.foxinmy.weixin4j.handler.WeixinMessageHandler @
* @throws WeixinException
*/ */
public WeixinMessageHandler[] getMessageHandlers() throws WeixinException { public WeixinMessageHandler[] getMessageHandlers() {
if (this.messageHandlers == null) { if (this.messageHandlers == null) {
if (messageHandlerPackages != null) { if (messageHandlerPackages != null) {
List<Class<?>> messageHandlerClass = new ArrayList<Class<?>>(); List<Class<?>> messageHandlerClass = new ArrayList<Class<?>>();
for (String packageName : messageHandlerPackages) { for (String packageName : messageHandlerPackages) {
messageHandlerClass.addAll(ClassUtil messageHandlerClass.addAll(ClassUtil.getClasses(packageName));
.getClasses(packageName));
} }
if (beanFactory != null) { if (beanFactory != null) {
for (Class<?> clazz : messageHandlerClass) { for (Class<?> clazz : messageHandlerClass) {
if (clazz.isInterface() if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())
|| Modifier.isAbstract(clazz.getModifiers()) || !WeixinMessageHandler.class.isAssignableFrom(clazz)) {
|| !WeixinMessageHandler.class
.isAssignableFrom(clazz)) {
continue; continue;
} }
try { try {
messageHandlerList messageHandlerList.add((WeixinMessageHandler) beanFactory.getBean(clazz));
.add((WeixinMessageHandler) beanFactory
.getBean(clazz));
} catch (RuntimeException ex) { // multiple } catch (RuntimeException ex) { // multiple
for (Object o : beanFactory.getBeans(clazz) for (Object o : beanFactory.getBeans(clazz).values()) {
.values()) {
if (o.getClass() == clazz) { if (o.getClass() == clazz) {
messageHandlerList messageHandlerList.add((WeixinMessageHandler) o);
.add((WeixinMessageHandler) o);
break; break;
} }
} }
@ -279,30 +250,23 @@ public class WeixinMessageDispatcher {
} }
} else { } else {
for (Class<?> clazz : messageHandlerClass) { for (Class<?> clazz : messageHandlerClass) {
if (clazz.isInterface() if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())
|| Modifier.isAbstract(clazz.getModifiers()) || !WeixinMessageHandler.class.isAssignableFrom(clazz)) {
|| !WeixinMessageHandler.class
.isAssignableFrom(clazz)) {
continue; continue;
} }
try { try {
Constructor<?> ctor = clazz Constructor<?> ctor = clazz.getDeclaredConstructor();
.getDeclaredConstructor();
ServerToolkits.makeConstructorAccessible(ctor); ServerToolkits.makeConstructorAccessible(ctor);
messageHandlerList.add((WeixinMessageHandler) ctor messageHandlerList.add((WeixinMessageHandler) ctor.newInstance((Object[]) null));
.newInstance((Object[]) null));
} catch (Exception ex) { } catch (Exception ex) {
throw new WeixinException(clazz.getName() throw new RuntimeException(clazz.getName() + " instantiate fail", ex);
+ " instantiate fail", ex);
} }
} }
} }
} }
if (messageHandlerList != null if (messageHandlerList != null && !this.messageHandlerList.isEmpty()) {
&& !this.messageHandlerList.isEmpty()) {
this.messageHandlers = this.messageHandlerList this.messageHandlers = this.messageHandlerList
.toArray(new WeixinMessageHandler[this.messageHandlerList .toArray(new WeixinMessageHandler[this.messageHandlerList.size()]);
.size()]);
} }
} }
return this.messageHandlers; return this.messageHandlers;
@ -312,36 +276,27 @@ public class WeixinMessageDispatcher {
* 获取所有的interceptor * 获取所有的interceptor
* *
* @return interceptor集合 * @return interceptor集合
* @throws WeixinException * @ @see com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor
* @see com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor
*/ */
public WeixinMessageInterceptor[] getMessageInterceptors() public WeixinMessageInterceptor[] getMessageInterceptors() {
throws WeixinException {
if (this.messageInterceptors == null) { if (this.messageInterceptors == null) {
if (this.messageInterceptorPackages != null) { if (this.messageInterceptorPackages != null) {
List<Class<?>> messageInterceptorClass = new ArrayList<Class<?>>(); List<Class<?>> messageInterceptorClass = new ArrayList<Class<?>>();
for (String packageName : messageInterceptorPackages) { for (String packageName : messageInterceptorPackages) {
messageInterceptorClass.addAll(ClassUtil messageInterceptorClass.addAll(ClassUtil.getClasses(packageName));
.getClasses(packageName));
} }
if (beanFactory != null) { if (beanFactory != null) {
for (Class<?> clazz : messageInterceptorClass) { for (Class<?> clazz : messageInterceptorClass) {
if (clazz.isInterface() if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())
|| Modifier.isAbstract(clazz.getModifiers()) || !WeixinMessageInterceptor.class.isAssignableFrom(clazz)) {
|| !WeixinMessageInterceptor.class
.isAssignableFrom(clazz)) {
continue; continue;
} }
try { try {
messageInterceptorList messageInterceptorList.add((WeixinMessageInterceptor) beanFactory.getBean(clazz));
.add((WeixinMessageInterceptor) beanFactory
.getBean(clazz));
} catch (RuntimeException ex) { // multiple } catch (RuntimeException ex) { // multiple
for (Object o : beanFactory.getBeans(clazz) for (Object o : beanFactory.getBeans(clazz).values()) {
.values()) {
if (o.getClass() == clazz) { if (o.getClass() == clazz) {
messageInterceptorList messageInterceptorList.add((WeixinMessageInterceptor) o);
.add((WeixinMessageInterceptor) o);
break; break;
} }
} }
@ -349,43 +304,32 @@ public class WeixinMessageDispatcher {
} }
} else { } else {
for (Class<?> clazz : messageInterceptorClass) { for (Class<?> clazz : messageInterceptorClass) {
if (clazz.isInterface() if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())
|| Modifier.isAbstract(clazz.getModifiers()) || !WeixinMessageInterceptor.class.isAssignableFrom(clazz)) {
|| !WeixinMessageInterceptor.class
.isAssignableFrom(clazz)) {
continue; continue;
} }
try { try {
Constructor<?> ctor = clazz Constructor<?> ctor = clazz.getDeclaredConstructor();
.getDeclaredConstructor();
ServerToolkits.makeConstructorAccessible(ctor); ServerToolkits.makeConstructorAccessible(ctor);
messageInterceptorList messageInterceptorList.add((WeixinMessageInterceptor) ctor.newInstance((Object[]) null));
.add((WeixinMessageInterceptor) ctor
.newInstance((Object[]) null));
} catch (Exception ex) { } catch (Exception ex) {
throw new WeixinException(clazz.getName() throw new RuntimeException(clazz.getName() + " instantiate fail", ex);
+ " instantiate fail", ex);
} }
} }
} }
} }
if (this.messageInterceptorList != null if (this.messageInterceptorList != null && !this.messageInterceptorList.isEmpty()) {
&& !this.messageInterceptorList.isEmpty()) { Collections.sort(messageInterceptorList, new Comparator<WeixinMessageInterceptor>() {
Collections.sort(messageInterceptorList,
new Comparator<WeixinMessageInterceptor>() {
@Override @Override
public int compare(WeixinMessageInterceptor m1, public int compare(WeixinMessageInterceptor m1, WeixinMessageInterceptor m2) {
WeixinMessageInterceptor m2) {
return m2.weight() - m1.weight(); return m2.weight() - m1.weight();
} }
}); });
this.messageInterceptors = this.messageInterceptorList this.messageInterceptors = this.messageInterceptorList
.toArray(new WeixinMessageInterceptor[this.messageInterceptorList .toArray(new WeixinMessageInterceptor[this.messageInterceptorList.size()]);
.size()]);
} }
} }
logger.info("resolve message interceptors '{}'", logger.info("resolve message interceptors '{}'", this.messageInterceptorList);
this.messageInterceptorList);
return this.messageInterceptors; return this.messageInterceptors;
} }
@ -396,22 +340,18 @@ public class WeixinMessageDispatcher {
* xml消息 * xml消息
* @param clazz * @param clazz
* 消息类型 * 消息类型
* @return 消息对象 * @return 消息对象 @
* @throws WeixinException
*/ */
protected <M extends WeixinMessage> M messageRead(String message, protected <M extends WeixinMessage> M messageRead(String message, Class<M> clazz) {
Class<M> clazz) throws WeixinException {
if (clazz == null) { if (clazz == null) {
return null; return null;
} }
try { try {
Source source = new StreamSource(new ByteArrayInputStream( Source source = new StreamSource(new ByteArrayInputStream(ServerToolkits.getBytesUtf8(message)));
ServerToolkits.getBytesUtf8(message))); JAXBElement<M> jaxbElement = getUnmarshaller(clazz).unmarshal(source, clazz);
JAXBElement<M> jaxbElement = getUnmarshaller(clazz).unmarshal(
source, clazz);
return jaxbElement.getValue(); return jaxbElement.getValue();
} catch (JAXBException e) { } catch (JAXBException e) {
throw new WeixinException(e); throw new RuntimeException(e);
} }
} }
@ -420,11 +360,9 @@ public class WeixinMessageDispatcher {
* *
* @param clazz * @param clazz
* 消息类型 * 消息类型
* @return 消息转换器 * @return 消息转换器 @
* @throws WeixinException
*/ */
protected Unmarshaller getUnmarshaller(Class<? extends WeixinMessage> clazz) protected Unmarshaller getUnmarshaller(Class<? extends WeixinMessage> clazz) {
throws WeixinException {
Unmarshaller unmarshaller = messageUnmarshaller.get(clazz); Unmarshaller unmarshaller = messageUnmarshaller.get(clazz);
if (unmarshaller == null) { if (unmarshaller == null) {
try { try {
@ -432,19 +370,17 @@ public class WeixinMessageDispatcher {
unmarshaller = jaxbContext.createUnmarshaller(); unmarshaller = jaxbContext.createUnmarshaller();
messageUnmarshaller.put(clazz, unmarshaller); messageUnmarshaller.put(clazz, unmarshaller);
} catch (JAXBException e) { } catch (JAXBException e) {
throw new WeixinException(e); throw new RuntimeException(e);
} }
} }
return unmarshaller; return unmarshaller;
} }
public void setMessageHandlerList( public void setMessageHandlerList(List<WeixinMessageHandler> messageHandlerList) {
List<WeixinMessageHandler> messageHandlerList) {
this.messageHandlerList = messageHandlerList; this.messageHandlerList = messageHandlerList;
} }
public void setMessageInterceptorList( public void setMessageInterceptorList(List<WeixinMessageInterceptor> messageInterceptorList) {
List<WeixinMessageInterceptor> messageInterceptorList) {
this.messageInterceptorList = messageInterceptorList; this.messageInterceptorList = messageInterceptorList;
} }
@ -460,8 +396,7 @@ public class WeixinMessageDispatcher {
this.messageHandlerPackages = messageHandlerPackages; this.messageHandlerPackages = messageHandlerPackages;
} }
public void setMessageInterceptorPackages( public void setMessageInterceptorPackages(String... messageInterceptorPackages) {
String... messageInterceptorPackages) {
this.messageInterceptorPackages = messageInterceptorPackages; this.messageInterceptorPackages = messageInterceptorPackages;
} }
@ -473,8 +408,7 @@ public class WeixinMessageDispatcher {
this.beanFactory = beanFactory; this.beanFactory = beanFactory;
} }
public void registMessageClass(WeixinMessageKey messageKey, public void registMessageClass(WeixinMessageKey messageKey, Class<? extends WeixinMessage> messageClass) {
Class<? extends WeixinMessage> messageClass) {
messageMatcher.regist(messageKey, messageClass); messageMatcher.regist(messageKey, messageClass);
} }

View File

@ -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;
}
}

View File

@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.handler;
import java.util.Set; import java.util.Set;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinMessage;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
import com.foxinmy.weixin4j.response.TextResponse; import com.foxinmy.weixin4j.response.TextResponse;
@ -26,16 +25,14 @@ public class DebugMessageHandler implements WeixinMessageHandler {
} }
@Override @Override
public boolean canHandle(WeixinRequest request, WeixinMessage message, public boolean canHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) {
Set<String> nodeNames) throws WeixinException {
return true; return true;
} }
@Override @Override
public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) {
Set<String> nodeNames) throws WeixinException { String content = message == null
String content = message == null ? request.getOriginalContent() ? request.getOriginalContent().replaceAll("\\!\\[CDATA\\[", "").replaceAll("\\]\\]", "")
.replaceAll("\\!\\[CDATA\\[", "").replaceAll("\\]\\]", "")
: message.toString(); : message.toString();
return new TextResponse(content); return new TextResponse(content);
} }

View File

@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.handler;
import java.util.Set; import java.util.Set;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinMessage;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.response.WeixinResponse;
@ -18,14 +17,11 @@ import com.foxinmy.weixin4j.util.ClassUtil;
* @see com.foxinmy.weixin4j.request.WeixinMessage * @see com.foxinmy.weixin4j.request.WeixinMessage
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public abstract class MessageHandlerAdapter<M extends WeixinMessage> implements public abstract class MessageHandlerAdapter<M extends WeixinMessage> implements WeixinMessageHandler {
WeixinMessageHandler {
@Override @Override
public boolean canHandle(WeixinRequest request, WeixinMessage message, public boolean canHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) {
Set<String> nodeNames) throws WeixinException { return message != null && message.getClass() == ClassUtil.getGenericType(getClass())
return message != null
&& message.getClass() == ClassUtil.getGenericType(getClass())
&& canHandle0(request, (M) message); && canHandle0(request, (M) message);
} }
@ -36,18 +32,14 @@ public abstract class MessageHandlerAdapter<M extends WeixinMessage> implements
* 微信请求 * 微信请求
* @param message * @param message
* 微信消息 * 微信消息
* @return true则执行doHandler0 * @return true则执行doHandler0 @
* @throws WeixinException
*/ */
public boolean canHandle0(WeixinRequest request, M message) public boolean canHandle0(WeixinRequest request, M message) {
throws WeixinException {
return true; return true;
} }
@Override @Override
public WeixinResponse doHandle(WeixinRequest request, public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) {
WeixinMessage message, Set<String> nodeNames)
throws WeixinException {
return doHandle0(request, (M) message); return doHandle0(request, (M) message);
} }
@ -60,8 +52,7 @@ public abstract class MessageHandlerAdapter<M extends WeixinMessage> implements
* 微信消息 * 微信消息
* @return * @return
*/ */
public abstract WeixinResponse doHandle0(WeixinRequest request, M message) public abstract WeixinResponse doHandle0(WeixinRequest request, M message);
throws WeixinException;
/** /**
* 缺省值为1,存在多个匹配到的MessageHandler则比较weight大小 * 缺省值为1,存在多个匹配到的MessageHandler则比较weight大小

View File

@ -3,7 +3,6 @@ package com.foxinmy.weixin4j.handler;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinMessage;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
@ -32,8 +31,7 @@ public abstract class MultipleMessageHandlerAdapter implements WeixinMessageHand
} }
@Override @Override
public boolean canHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) public boolean canHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) {
throws WeixinException {
return message != null && messageClasses.contains(message.getClass()) && canHandle0(request, message); return message != null && messageClasses.contains(message.getClass()) && canHandle0(request, message);
} }
@ -47,7 +45,7 @@ public abstract class MultipleMessageHandlerAdapter implements WeixinMessageHand
* @return true则执行doHandler * @return true则执行doHandler
* @throws WeixinException * @throws WeixinException
*/ */
public boolean canHandle0(WeixinRequest request, WeixinMessage message) throws WeixinException { public boolean canHandle0(WeixinRequest request, WeixinMessage message) {
return true; return true;
} }

View File

@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.handler;
import java.util.Set; import java.util.Set;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinMessage;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.response.WeixinResponse;
@ -30,8 +29,7 @@ public interface WeixinMessageHandler {
* 节点名称集合 * 节点名称集合
* @return true则执行doHandle * @return true则执行doHandle
*/ */
public boolean canHandle(WeixinRequest request, WeixinMessage message, public boolean canHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames);
Set<String> nodeNames) throws WeixinException;
/** /**
* 处理请求 * 处理请求
@ -44,8 +42,7 @@ public interface WeixinMessageHandler {
* 节点名称集合 * 节点名称集合
* @return 回复内容 * @return 回复内容
*/ */
public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames);
Set<String> nodeNames) throws WeixinException;
/** /**
* 用于匹配到多个MessageHandler时权重降序排列,数字越大优先级越高 * 用于匹配到多个MessageHandler时权重降序排列,数字越大优先级越高

View File

@ -1,13 +1,12 @@
package com.foxinmy.weixin4j.interceptor; 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.handler.WeixinMessageHandler;
import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinMessage;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.response.WeixinResponse;
import io.netty.channel.ChannelHandlerContext;
/** /**
* 消息拦截适配 * 消息拦截适配
* *
@ -17,27 +16,22 @@ import com.foxinmy.weixin4j.response.WeixinResponse;
* @since JDK 1.6 * @since JDK 1.6
* @see * @see
*/ */
public abstract class MessageInterceptorAdapter implements public abstract class MessageInterceptorAdapter implements WeixinMessageInterceptor {
WeixinMessageInterceptor {
@Override @Override
public boolean preHandle(ChannelHandlerContext context, public boolean preHandle(ChannelHandlerContext context, WeixinRequest request, WeixinMessage message,
WeixinRequest request, WeixinMessage message, WeixinMessageHandler handler) WeixinMessageHandler handler) {
throws WeixinException {
return true; return true;
} }
@Override @Override
public void postHandle(ChannelHandlerContext context, public void postHandle(ChannelHandlerContext context, WeixinRequest request, WeixinResponse response,
WeixinRequest request, WeixinResponse response, WeixinMessage message, WeixinMessage message, WeixinMessageHandler handler) {
WeixinMessageHandler handler) throws WeixinException {
} }
@Override @Override
public void afterCompletion(ChannelHandlerContext context, public void afterCompletion(ChannelHandlerContext context, WeixinRequest request, WeixinResponse response,
WeixinRequest request, WeixinResponse response, WeixinMessage message, WeixinMessage message, WeixinMessageHandler handler, Exception exception) {
WeixinMessageHandler handler, Exception exception)
throws WeixinException {
} }
@Override @Override

View File

@ -1,13 +1,12 @@
package com.foxinmy.weixin4j.interceptor; 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.handler.WeixinMessageHandler;
import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinMessage;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.response.WeixinResponse;
import io.netty.channel.ChannelHandlerContext;
/** /**
* 微信消息拦截器 * 微信消息拦截器
* *
@ -34,8 +33,7 @@ public interface WeixinMessageInterceptor {
* @throws WeixinException * @throws WeixinException
*/ */
boolean preHandle(ChannelHandlerContext context, WeixinRequest request, boolean preHandle(ChannelHandlerContext context, WeixinRequest request,
WeixinMessage message, WeixinMessageHandler handler) WeixinMessage message, WeixinMessageHandler handler);
throws WeixinException;
/** /**
* 执行handler后 * 执行handler后
@ -54,7 +52,7 @@ public interface WeixinMessageInterceptor {
*/ */
void postHandle(ChannelHandlerContext context, WeixinRequest request, void postHandle(ChannelHandlerContext context, WeixinRequest request,
WeixinResponse response, WeixinMessage message, WeixinResponse response, WeixinMessage message,
WeixinMessageHandler handler) throws WeixinException; WeixinMessageHandler handler);
/** /**
* 全部执行后 * 全部执行后
@ -73,8 +71,7 @@ public interface WeixinMessageInterceptor {
*/ */
void afterCompletion(ChannelHandlerContext context, WeixinRequest request, void afterCompletion(ChannelHandlerContext context, WeixinRequest request,
WeixinResponse response, WeixinMessage message, WeixinResponse response, WeixinMessage message,
WeixinMessageHandler handler, Exception exception) WeixinMessageHandler handler, Exception exception);
throws WeixinException;
/** /**
* 用于匹配到多个MessageHandler时权重降序排列,数字越大优先级越高 * 用于匹配到多个MessageHandler时权重降序排列,数字越大优先级越高

View File

@ -1,18 +1,17 @@
package com.foxinmy.weixin4j.socket; 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.ChannelHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory; 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;
/** /**
* 单一回复编码类 * 单一回复编码类
* *
@ -23,18 +22,14 @@ import com.foxinmy.weixin4j.util.ServerToolkits;
* @see com.foxinmy.weixin4j.response.SingleResponse * @see com.foxinmy.weixin4j.response.SingleResponse
*/ */
@ChannelHandler.Sharable @ChannelHandler.Sharable
public class SingleResponseEncoder extends public class SingleResponseEncoder extends MessageToMessageEncoder<SingleResponse> {
MessageToMessageEncoder<SingleResponse> {
private final InternalLogger logger = InternalLoggerFactory private final InternalLogger logger = InternalLoggerFactory.getInstance(getClass());
.getInstance(getClass());
@Override @Override
protected void encode(ChannelHandlerContext ctx, SingleResponse response, protected void encode(ChannelHandlerContext ctx, SingleResponse response, List<Object> out) {
List<Object> out) throws WeixinException {
String content = response.toContent(); String content = response.toContent();
ctx.writeAndFlush(HttpUtil.createHttpResponse(content, ctx.writeAndFlush(HttpUtil.createHttpResponse(content, ServerToolkits.CONTENTTYPE$TEXT_PLAIN));
ServerToolkits.CONTENTTYPE$TEXT_PLAIN));
logger.info("encode single response:{}", content); logger.info("encode single response:{}", content);
} }
} }

View File

@ -5,7 +5,6 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
import com.foxinmy.weixin4j.type.EncryptType; import com.foxinmy.weixin4j.type.EncryptType;
import com.foxinmy.weixin4j.util.AesToken; import com.foxinmy.weixin4j.util.AesToken;
@ -50,7 +49,7 @@ public class WeixinMessageDecoder extends MessageToMessageDecoder<FullHttpReques
} }
@Override @Override
protected void decode(ChannelHandlerContext ctx, FullHttpRequest req, List<Object> out) throws WeixinException { protected void decode(ChannelHandlerContext ctx, FullHttpRequest req, List<Object> out) {
String messageContent = req.content().toString(ServerToolkits.UTF_8); String messageContent = req.content().toString(ServerToolkits.UTF_8);
QueryStringDecoder queryDecoder = new QueryStringDecoder(req.uri(), true); QueryStringDecoder queryDecoder = new QueryStringDecoder(req.uri(), true);
HttpMethod method = req.method(); HttpMethod method = req.method();
@ -68,7 +67,7 @@ public class WeixinMessageDecoder extends MessageToMessageDecoder<FullHttpReques
String encryptContent = null; String encryptContent = null;
if (!ServerToolkits.isBlank(messageContent) && encryptType == EncryptType.AES) { if (!ServerToolkits.isBlank(messageContent) && encryptType == EncryptType.AES) {
if (ServerToolkits.isBlank(aesToken.getAesKey())) { if (ServerToolkits.isBlank(aesToken.getAesKey())) {
throw new WeixinException("EncodingAESKey not be empty in safety(AES) mode"); throw new RuntimeException("EncodingAESKey not be empty in safety(AES) mode");
} }
EncryptMessageHandler encryptHandler = EncryptMessageHandler.parser(messageContent); EncryptMessageHandler encryptHandler = EncryptMessageHandler.parser(messageContent);
encryptContent = encryptHandler.getEncryptContent(); encryptContent = encryptHandler.getEncryptContent();

View File

@ -3,6 +3,16 @@ package com.foxinmy.weixin4j.socket;
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST; import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN; import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
import static io.netty.handler.codec.http.HttpResponseStatus.METHOD_NOT_ALLOWED; import static io.netty.handler.codec.http.HttpResponseStatus.METHOD_NOT_ALLOWED;
import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher;
import com.foxinmy.weixin4j.request.WeixinRequest;
import com.foxinmy.weixin4j.response.SingleResponse;
import com.foxinmy.weixin4j.type.EncryptType;
import com.foxinmy.weixin4j.util.AesToken;
import com.foxinmy.weixin4j.util.HttpUtil;
import com.foxinmy.weixin4j.util.MessageUtil;
import com.foxinmy.weixin4j.util.ServerToolkits;
import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
@ -13,16 +23,6 @@ import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.util.internal.logging.InternalLoggerFactory;
import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.request.WeixinRequest;
import com.foxinmy.weixin4j.response.SingleResponse;
import com.foxinmy.weixin4j.type.EncryptType;
import com.foxinmy.weixin4j.util.AesToken;
import com.foxinmy.weixin4j.util.HttpUtil;
import com.foxinmy.weixin4j.util.MessageUtil;
import com.foxinmy.weixin4j.util.ServerToolkits;
/** /**
* 微信请求处理类 * 微信请求处理类
* *
@ -32,10 +32,8 @@ import com.foxinmy.weixin4j.util.ServerToolkits;
* @since JDK 1.6 * @since JDK 1.6
* @see com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher * @see com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher
*/ */
public class WeixinRequestHandler extends public class WeixinRequestHandler extends SimpleChannelInboundHandler<WeixinRequest> {
SimpleChannelInboundHandler<WeixinRequest> { private final InternalLogger logger = InternalLoggerFactory.getInstance(getClass());
private final InternalLogger logger = InternalLoggerFactory
.getInstance(getClass());
private final WeixinMessageDispatcher messageDispatcher; private final WeixinMessageDispatcher messageDispatcher;
@ -54,15 +52,12 @@ public class WeixinRequestHandler extends
} }
@Override @Override
protected void channelRead0(ChannelHandlerContext ctx, WeixinRequest request) protected void channelRead0(ChannelHandlerContext ctx, WeixinRequest request) {
throws WeixinException {
AesToken aesToken = request.getAesToken(); AesToken aesToken = request.getAesToken();
// 消息字段不完整返回400 // 消息字段不完整返回400
if (aesToken == null if (aesToken == null || (ServerToolkits.isBlank(request.getSignature())
|| (ServerToolkits.isBlank(request.getSignature()) && ServerToolkits && ServerToolkits.isBlank(request.getMsgSignature()))) {
.isBlank(request.getMsgSignature()))) { ctx.writeAndFlush(resolveResponse(BAD_REQUEST, request)).addListener(ChannelFutureListener.CLOSE);
ctx.writeAndFlush(resolveResponse(BAD_REQUEST, request))
.addListener(ChannelFutureListener.CLOSE);
return; return;
} }
/** /**
@ -73,58 +68,46 @@ public class WeixinRequestHandler extends
if (request.getMethod() == HttpMethod.GET) { if (request.getMethod() == HttpMethod.GET) {
// URL参数签名验证 // URL参数签名验证
if (!ServerToolkits.isBlank(request.getSignature()) if (!ServerToolkits.isBlank(request.getSignature())
&& MessageUtil.signature(aesToken.getToken(), && MessageUtil.signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce())
request.getTimeStamp(), request.getNonce()).equals( .equals(request.getSignature())) {
request.getSignature())) {
ctx.writeAndFlush(new SingleResponse(request.getEchoStr())); ctx.writeAndFlush(new SingleResponse(request.getEchoStr()));
return; return;
} }
// XML消息签名验证 // XML消息签名验证
if (!ServerToolkits.isBlank(request.getMsgSignature()) if (!ServerToolkits.isBlank(request.getMsgSignature()) && MessageUtil
&& MessageUtil.signature(aesToken.getToken(), .signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce(), request.getEchoStr())
request.getTimeStamp(), request.getNonce(), .equals(request.getMsgSignature())) {
request.getEchoStr()).equals( ctx.writeAndFlush(
request.getMsgSignature())) { new SingleResponse(MessageUtil.aesDecrypt(null, aesToken.getAesKey(), request.getEchoStr())));
ctx.writeAndFlush(new SingleResponse(MessageUtil.aesDecrypt(
null, aesToken.getAesKey(), request.getEchoStr())));
return; return;
} }
ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)).addListener( ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)).addListener(ChannelFutureListener.CLOSE);
ChannelFutureListener.CLOSE);
return; return;
} else if (request.getMethod() == HttpMethod.POST) { } else if (request.getMethod() == HttpMethod.POST) {
// URL参数签名验证 // URL参数签名验证
if (!ServerToolkits.isBlank(request.getSignature()) if (!ServerToolkits.isBlank(request.getSignature())
&& !MessageUtil.signature(aesToken.getToken(), && !MessageUtil.signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce())
request.getTimeStamp(), request.getNonce()).equals( .equals(request.getSignature())) {
request.getSignature())) { ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)).addListener(ChannelFutureListener.CLOSE);
ctx.writeAndFlush(resolveResponse(FORBIDDEN, request))
.addListener(ChannelFutureListener.CLOSE);
return; return;
} }
// XML消息签名验证 // XML消息签名验证
if (request.getEncryptType() == EncryptType.AES if (request.getEncryptType() == EncryptType.AES
&& !MessageUtil.signature(aesToken.getToken(), && !MessageUtil.signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce(),
request.getTimeStamp(), request.getNonce(), request.getEncryptContent()).equals(request.getMsgSignature())) {
request.getEncryptContent()).equals( ctx.writeAndFlush(resolveResponse(FORBIDDEN, request)).addListener(ChannelFutureListener.CLOSE);
request.getMsgSignature())) {
ctx.writeAndFlush(resolveResponse(FORBIDDEN, request))
.addListener(ChannelFutureListener.CLOSE);
return; return;
} }
} else { } else {
// 访问其它URL // 访问其它URL
ctx.writeAndFlush(resolveResponse(METHOD_NOT_ALLOWED, request)) ctx.writeAndFlush(resolveResponse(METHOD_NOT_ALLOWED, request)).addListener(ChannelFutureListener.CLOSE);
.addListener(ChannelFutureListener.CLOSE);
return; return;
} }
messageDispatcher.doDispatch(ctx, request); messageDispatcher.doDispatch(ctx, request);
} }
private FullHttpResponse resolveResponse(HttpResponseStatus responseStatus, private FullHttpResponse resolveResponse(HttpResponseStatus responseStatus, WeixinRequest request) {
WeixinRequest request) { FullHttpResponse response = new DefaultFullHttpResponse(request.getProtocolVersion(), responseStatus);
FullHttpResponse response = new DefaultFullHttpResponse(
request.getProtocolVersion(), responseStatus);
HttpUtil.resolveHeaders(response); HttpUtil.resolveHeaders(response);
return response; return response;
} }

View File

@ -1,14 +1,7 @@
package com.foxinmy.weixin4j.socket; 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 java.util.List;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.response.WeixinResponse;
import com.foxinmy.weixin4j.type.EncryptType; import com.foxinmy.weixin4j.type.EncryptType;
import com.foxinmy.weixin4j.util.AesToken; 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.MessageUtil;
import com.foxinmy.weixin4j.util.ServerToolkits; 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,16 +22,14 @@ import com.foxinmy.weixin4j.util.ServerToolkits;
* @author jinyu(foxinmy@gmail.com) * @author jinyu(foxinmy@gmail.com)
* @date 2014年11月13日 * @date 2014年11月13日
* @since JDK 1.6 * @since JDK 1.6
* @see <a * @see <a href=
* href="http://mp.weixin.qq.com/wiki/0/61c3a8b9d50ac74f18bdf2e54ddfc4e0.html">加密接入指引</a> * "http://mp.weixin.qq.com/wiki/0/61c3a8b9d50ac74f18bdf2e54ddfc4e0.html">加密接入指引</a>
* @see com.foxinmy.weixin4j.response.WeixinResponse * @see com.foxinmy.weixin4j.response.WeixinResponse
*/ */
@ChannelHandler.Sharable @ChannelHandler.Sharable
public class WeixinResponseEncoder extends public class WeixinResponseEncoder extends MessageToMessageEncoder<WeixinResponse> {
MessageToMessageEncoder<WeixinResponse> {
protected final InternalLogger logger = InternalLoggerFactory protected final InternalLogger logger = InternalLoggerFactory.getInstance(getClass());
.getInstance(getClass());
private final String XML_START = "<xml>"; private final String XML_START = "<xml>";
// ---------------明文节点 // ---------------明文节点
@ -48,31 +45,23 @@ public class WeixinResponseEncoder extends
private final String XML_END = "</xml>"; private final String XML_END = "</xml>";
@Override @Override
protected void encode(ChannelHandlerContext ctx, WeixinResponse response, protected void encode(ChannelHandlerContext ctx, WeixinResponse response, List<Object> out) {
List<Object> out) throws WeixinException { WeixinMessageTransfer messageTransfer = ctx.channel().attr(ServerToolkits.MESSAGE_TRANSFER_KEY).get();
WeixinMessageTransfer messageTransfer = ctx.channel()
.attr(ServerToolkits.MESSAGE_TRANSFER_KEY).get();
EncryptType encryptType = messageTransfer.getEncryptType(); EncryptType encryptType = messageTransfer.getEncryptType();
StringBuilder content = new StringBuilder(); StringBuilder content = new StringBuilder();
content.append(XML_START); content.append(XML_START);
content.append(String.format(ELEMENT_TOUSERNAME, content.append(String.format(ELEMENT_TOUSERNAME, messageTransfer.getFromUserName()));
messageTransfer.getFromUserName())); content.append(String.format(ELEMENT_FROMUSERNAME, messageTransfer.getToUserName()));
content.append(String.format(ELEMENT_FROMUSERNAME, content.append(String.format(ELEMENT_CREATETIME, System.currentTimeMillis() / 1000l));
messageTransfer.getToUserName()));
content.append(String.format(ELEMENT_CREATETIME,
System.currentTimeMillis() / 1000l));
content.append(String.format(ELEMENT_MSGTYPE, response.getMsgType())); content.append(String.format(ELEMENT_MSGTYPE, response.getMsgType()));
content.append(response.toContent()); content.append(response.toContent());
content.append(XML_END); content.append(XML_END);
if (encryptType == EncryptType.AES) { if (encryptType == EncryptType.AES) {
AesToken aesToken = messageTransfer.getAesToken(); AesToken aesToken = messageTransfer.getAesToken();
String nonce = ServerToolkits.generateRandomString(32); String nonce = ServerToolkits.generateRandomString(32);
String timestamp = Long String timestamp = Long.toString(System.currentTimeMillis() / 1000l);
.toString(System.currentTimeMillis() / 1000l); String encrtypt = MessageUtil.aesEncrypt(aesToken.getWeixinId(), aesToken.getAesKey(), content.toString());
String encrtypt = MessageUtil.aesEncrypt(aesToken.getWeixinId(), String msgSignature = MessageUtil.signature(aesToken.getToken(), nonce, timestamp, encrtypt);
aesToken.getAesKey(), content.toString());
String msgSignature = MessageUtil.signature(aesToken.getToken(),
nonce, timestamp, encrtypt);
content.delete(0, content.length()); content.delete(0, content.length());
content.append(XML_START); content.append(XML_START);
content.append(String.format(ELEMENT_NONCE, nonce)); content.append(String.format(ELEMENT_NONCE, nonce));
@ -81,8 +70,7 @@ public class WeixinResponseEncoder extends
content.append(String.format(ELEMENT_ENCRYPT, encrtypt)); content.append(String.format(ELEMENT_ENCRYPT, encrtypt));
content.append(XML_END); content.append(XML_END);
} }
ctx.writeAndFlush(HttpUtil.createHttpResponse(content.toString(), ctx.writeAndFlush(HttpUtil.createHttpResponse(content.toString(), ServerToolkits.CONTENTTYPE$APPLICATION_XML));
ServerToolkits.CONTENTTYPE$APPLICATION_XML));
logger.info("{} encode weixin response:{}", encryptType, content); logger.info("{} encode weixin response:{}", encryptType, content);
} }
} }

View File

@ -5,7 +5,6 @@ import java.util.Map;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import com.foxinmy.weixin4j.dispatcher.BeanFactory; import com.foxinmy.weixin4j.dispatcher.BeanFactory;
import com.foxinmy.weixin4j.exception.WeixinException;
/** /**
* 使用spring容器获取bean * 使用spring容器获取bean
@ -25,22 +24,22 @@ public class SpringBeanFactory implements BeanFactory {
} }
@Override @Override
public Object getBean(String name) throws WeixinException { public Object getBean(String name) {
return context.getBean(name); return context.getBean(name);
} }
@Override @Override
public <T> T getBean(Class<T> classType) throws WeixinException { public <T> T getBean(Class<T> classType) {
return context.getBean(classType); return context.getBean(classType);
} }
@Override @Override
public <T> T getBean(String name, Class<T> classType) throws WeixinException { public <T> T getBean(String name, Class<T> classType) {
return context.getBean(name, classType); return context.getBean(name, classType);
} }
@Override @Override
public <T> Map<String, T> getBeans(Class<T> clazz) throws WeixinException { public <T> Map<String, T> getBeans(Class<T> clazz) {
return context.getBeansOfType(clazz); return context.getBeansOfType(clazz);
} }
} }

View File

@ -11,7 +11,6 @@ import com.foxinmy.weixin4j.dispatcher.DefaultMessageMatcher;
import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher; import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher;
import com.foxinmy.weixin4j.dispatcher.WeixinMessageKey; import com.foxinmy.weixin4j.dispatcher.WeixinMessageKey;
import com.foxinmy.weixin4j.dispatcher.WeixinMessageMatcher; import com.foxinmy.weixin4j.dispatcher.WeixinMessageMatcher;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.handler.WeixinMessageHandler;
import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor; import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor;
import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinMessage;
@ -173,7 +172,7 @@ public final class WeixinServerBootstrap {
* 默认端口(30000)启动服务 * 默认端口(30000)启动服务
* *
*/ */
public void startup() throws WeixinException { public void startup() {
startup(DEFAULT_SERVERPORT); 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); startup(DEFAULT_BOSSTHREADS, DEFAULT_WORKERTHREADS, serverPort);
} }
@ -197,7 +196,7 @@ public final class WeixinServerBootstrap {
* @return * @return
* @throws WeixinException * @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.setMessageHandlerList(messageHandlerList);
messageDispatcher.setMessageInterceptorList(messageInterceptorList); messageDispatcher.setMessageInterceptorList(messageInterceptorList);
try { try {
@ -218,7 +217,7 @@ public final class WeixinServerBootstrap {
}).sync().channel(); }).sync().channel();
ch.closeFuture().sync(); ch.closeFuture().sync();
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw new WeixinException("netty server startup FAIL", e); throw new RuntimeException(e);
} finally { } finally {
shutdown(); shutdown();
} }

View File

@ -18,8 +18,6 @@ import java.util.List;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import com.foxinmy.weixin4j.exception.WeixinException;
/** /**
* 对class的获取 * 对class的获取
* *
@ -40,8 +38,7 @@ public final class ClassUtil {
* 包名 * 包名
* @return * @return
*/ */
public static List<Class<?>> getClasses(String packageName) public static List<Class<?>> getClasses(String packageName) {
throws WeixinException {
String packageFileName = packageName.replace(POINT, File.separator); String packageFileName = packageName.replace(POINT, File.separator);
URL fullPath = getDefaultClassLoader().getResource(packageFileName); URL fullPath = getDefaultClassLoader().getResource(packageFileName);
String protocol = fullPath.getProtocol(); String protocol = fullPath.getProtocol();
@ -50,16 +47,13 @@ public final class ClassUtil {
File dir = new File(fullPath.toURI()); File dir = new File(fullPath.toURI());
return findClassesByFile(dir, packageName); return findClassesByFile(dir, packageName);
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
throw new WeixinException(e); throw new RuntimeException(e);
} }
} else if (protocol.equals(ServerToolkits.PROTOCOL_JAR)) { } else if (protocol.equals(ServerToolkits.PROTOCOL_JAR)) {
try { try {
return findClassesByJar( return findClassesByJar(((JarURLConnection) fullPath.openConnection()).getJarFile(), packageName);
((JarURLConnection) fullPath.openConnection())
.getJarFile(),
packageName);
} catch (IOException e) { } catch (IOException e) {
throw new WeixinException(e); throw new RuntimeException(e);
} }
} }
return null; return null;
@ -85,12 +79,10 @@ public final class ClassUtil {
if (files != null) { if (files != null) {
for (File file : files) { for (File file : files) {
if (file.isDirectory()) { if (file.isDirectory()) {
classes.addAll(findClassesByFile(file, packageName + POINT classes.addAll(findClassesByFile(file, packageName + POINT + file.getName()));
+ file.getName()));
} else { } else {
try { try {
classes.add(Class.forName(packageName + POINT classes.add(Class.forName(packageName + POINT + file.getName().replace(CLASS, "")));
+ file.getName().replace(CLASS, "")));
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
; ;
} }
@ -109,8 +101,7 @@ public final class ClassUtil {
* 包的全限类名 * 包的全限类名
* @return * @return
*/ */
private static List<Class<?>> findClassesByJar(JarFile jar, private static List<Class<?>> findClassesByJar(JarFile jar, String packageName) {
String packageName) {
List<Class<?>> classes = new ArrayList<Class<?>>(); List<Class<?>> classes = new ArrayList<Class<?>>();
Enumeration<JarEntry> jarEntries = jar.entries(); Enumeration<JarEntry> jarEntries = jar.entries();
while (jarEntries.hasMoreElements()) { while (jarEntries.hasMoreElements()) {
@ -118,10 +109,8 @@ public final class ClassUtil {
if (jarEntry.isDirectory()) { if (jarEntry.isDirectory()) {
continue; continue;
} }
String className = jarEntry.getName() String className = jarEntry.getName().replace(File.separator, POINT);
.replace(File.separator, POINT); if (!className.startsWith(packageName) || !className.endsWith(CLASS)) {
if (!className.startsWith(packageName)
|| !className.endsWith(CLASS)) {
continue; continue;
} }
try { try {
@ -133,7 +122,7 @@ public final class ClassUtil {
return classes; return classes;
} }
public static Object deepClone(Object obj) throws WeixinException { public static Object deepClone(Object obj) {
ByteArrayOutputStream bos = null; ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null; ObjectOutputStream oos = null;
ByteArrayInputStream bis = null; ByteArrayInputStream bis = null;
@ -146,9 +135,9 @@ public final class ClassUtil {
ois = new ObjectInputStream(bis); ois = new ObjectInputStream(bis);
return ois.readObject(); return ois.readObject();
} catch (IOException e) { } catch (IOException e) {
throw new WeixinException(e); throw new RuntimeException(e);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
throw new WeixinException(e); throw new RuntimeException(e);
} finally { } finally {
try { try {
if (bos != null) { if (bos != null) {
@ -212,7 +201,7 @@ public final class ClassUtil {
return cl; return cl;
} }
public static void main(String[] args) throws WeixinException { public static void main(String[] args) {
System.err.println(getClasses("com.foxinmy.weixin4j.qy.event")); System.err.println(getClasses("com.foxinmy.weixin4j.qy.event"));
} }
} }

View File

@ -7,7 +7,6 @@ import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import com.foxinmy.weixin4j.base64.Base64; import com.foxinmy.weixin4j.base64.Base64;
import com.foxinmy.weixin4j.exception.WeixinException;
/** /**
* 消息工具类 * 消息工具类
@ -26,8 +25,8 @@ public final class MessageUtil {
* 微信加密签名signature结合了开发者填写的token参数和请求中的timestamp参数nonce参数 * 微信加密签名signature结合了开发者填写的token参数和请求中的timestamp参数nonce参数
* @return 开发者通过检验signature对请求进行相关校验若确认此次GET请求来自微信服务器 * @return 开发者通过检验signature对请求进行相关校验若确认此次GET请求来自微信服务器
* 请原样返回echostr参数内容则接入生效 成为开发者成功否则接入失败 * 请原样返回echostr参数内容则接入生效 成为开发者成功否则接入失败
* @see <a * @see <a href=
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN">接入指南</a> * "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN">接入指南</a>
*/ */
public static String signature(String... para) { public static String signature(String... para) {
Arrays.sort(para); Arrays.sort(para);
@ -50,16 +49,14 @@ public final class MessageUtil {
* @return aes加密后的消息体 * @return aes加密后的消息体
* @throws WeixinException * @throws WeixinException
*/ */
public static String aesEncrypt(String appId, String encodingAesKey, public static String aesEncrypt(String appId, String encodingAesKey, String xmlContent) {
String xmlContent) throws WeixinException {
/** /**
* 其中msg_encrypt=Base64_Encode(AES_Encrypt [random(16B)+ msg_len(4B) + * 其中msg_encrypt=Base64_Encode(AES_Encrypt [random(16B)+ msg_len(4B) +
* msg + $AppId]) * msg + $AppId])
* *
* random(16B)为16字节的随机字符串msg_len为msg长度占4个字节(网络字节序)$AppId为公众账号的AppId * random(16B)为16字节的随机字符串msg_len为msg长度占4个字节(网络字节序)$AppId为公众账号的AppId
*/ */
byte[] randomBytes = ServerToolkits.getBytesUtf8(ServerToolkits byte[] randomBytes = ServerToolkits.getBytesUtf8(ServerToolkits.generateRandomString(16));
.generateRandomString(16));
byte[] xmlBytes = ServerToolkits.getBytesUtf8(xmlContent); byte[] xmlBytes = ServerToolkits.getBytesUtf8(xmlContent);
int xmlLength = xmlBytes.length; int xmlLength = xmlBytes.length;
byte[] orderBytes = new byte[4]; byte[] orderBytes = new byte[4];
@ -69,24 +66,20 @@ public final class MessageUtil {
orderBytes[0] = (byte) (xmlLength >> 24 & 0xFF); orderBytes[0] = (byte) (xmlLength >> 24 & 0xFF);
byte[] appidBytes = ServerToolkits.getBytesUtf8(appId); byte[] appidBytes = ServerToolkits.getBytesUtf8(appId);
int byteLength = randomBytes.length + xmlLength + orderBytes.length int byteLength = randomBytes.length + xmlLength + orderBytes.length + appidBytes.length;
+ appidBytes.length;
// ... + pad: 使用自定义的填充方式对明文进行补位填充 // ... + pad: 使用自定义的填充方式对明文进行补位填充
byte[] padBytes = PKCS7Encoder.encode(byteLength); byte[] padBytes = PKCS7Encoder.encode(byteLength);
// random + endian + xml + appid + pad 获得最终的字节流 // random + endian + xml + appid + pad 获得最终的字节流
byte[] unencrypted = new byte[byteLength + padBytes.length]; byte[] unencrypted = new byte[byteLength + padBytes.length];
byteLength = 0; byteLength = 0;
// src:源数组;srcPos:源数组要复制的起始位置;dest:目的数组;destPos:目的数组放置的起始位置;length:复制的长度 // src:源数组;srcPos:源数组要复制的起始位置;dest:目的数组;destPos:目的数组放置的起始位置;length:复制的长度
System.arraycopy(randomBytes, 0, unencrypted, byteLength, System.arraycopy(randomBytes, 0, unencrypted, byteLength, randomBytes.length);
randomBytes.length);
byteLength += randomBytes.length; byteLength += randomBytes.length;
System.arraycopy(orderBytes, 0, unencrypted, byteLength, System.arraycopy(orderBytes, 0, unencrypted, byteLength, orderBytes.length);
orderBytes.length);
byteLength += orderBytes.length; byteLength += orderBytes.length;
System.arraycopy(xmlBytes, 0, unencrypted, byteLength, xmlBytes.length); System.arraycopy(xmlBytes, 0, unencrypted, byteLength, xmlBytes.length);
byteLength += xmlBytes.length; byteLength += xmlBytes.length;
System.arraycopy(appidBytes, 0, unencrypted, byteLength, System.arraycopy(appidBytes, 0, unencrypted, byteLength, appidBytes.length);
appidBytes.length);
byteLength += appidBytes.length; byteLength += appidBytes.length;
System.arraycopy(padBytes, 0, unencrypted, byteLength, padBytes.length); System.arraycopy(padBytes, 0, unencrypted, byteLength, padBytes.length);
try { try {
@ -100,10 +93,9 @@ public final class MessageUtil {
byte[] encrypted = cipher.doFinal(unencrypted); byte[] encrypted = cipher.doFinal(unencrypted);
// 使用BASE64对加密后的字符串进行编码 // 使用BASE64对加密后的字符串进行编码
// return Base64.encodeBase64String(encrypted); // return Base64.encodeBase64String(encrypted);
return Base64 return Base64.encodeBase64String(encrypted);
.encodeBase64String(encrypted);
} catch (Exception e) { } catch (Exception e) {
throw new WeixinException("-40006", "AES加密失败:" + e.getMessage()); throw new RuntimeException("-40006,AES加密失败:" + e.getMessage());
} }
} }
@ -118,23 +110,21 @@ public final class MessageUtil {
* @return 解密后的字符 * @return 解密后的字符
* @throws WeixinException * @throws WeixinException
*/ */
public static String aesDecrypt(String appId, String encodingAesKey, public static String aesDecrypt(String appId, String encodingAesKey, String encryptContent) {
String encryptContent) throws WeixinException {
byte[] aesKey = Base64.decodeBase64(encodingAesKey + "="); byte[] aesKey = Base64.decodeBase64(encodingAesKey + "=");
byte[] original; byte[] original;
try { try {
// 设置解密模式为AES的CBC模式 // 设置解密模式为AES的CBC模式
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec key_spec = new SecretKeySpec(aesKey, ServerToolkits.AES); SecretKeySpec key_spec = new SecretKeySpec(aesKey, ServerToolkits.AES);
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
0, 16));
cipher.init(Cipher.DECRYPT_MODE, key_spec, iv); cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
// 使用BASE64对密文进行解码 // 使用BASE64对密文进行解码
byte[] encrypted = Base64.decodeBase64(encryptContent); byte[] encrypted = Base64.decodeBase64(encryptContent);
// 解密 // 解密
original = cipher.doFinal(encrypted); original = cipher.doFinal(encrypted);
} catch (Exception e) { } catch (Exception e) {
throw new WeixinException("-40007", "AES解密失败:" + e.getMessage()); throw new RuntimeException("-40007,AES解密失败:" + e.getMessage());
} }
String xmlContent, fromAppId; String xmlContent, fromAppId;
try { try {
@ -148,20 +138,16 @@ public final class MessageUtil {
byte[] lengthByte = Arrays.copyOfRange(bytes, 16, 20); byte[] lengthByte = Arrays.copyOfRange(bytes, 16, 20);
// 获取xml消息主体的长度(byte[]2int) // 获取xml消息主体的长度(byte[]2int)
// http://my.oschina.net/u/169390/blog/97495 // http://my.oschina.net/u/169390/blog/97495
int xmlLength = lengthByte[3] & 0xff | (lengthByte[2] & 0xff) << 8 int xmlLength = lengthByte[3] & 0xff | (lengthByte[2] & 0xff) << 8 | (lengthByte[1] & 0xff) << 16
| (lengthByte[1] & 0xff) << 16
| (lengthByte[0] & 0xff) << 24; | (lengthByte[0] & 0xff) << 24;
xmlContent = ServerToolkits.newStringUtf8(Arrays.copyOfRange(bytes, 20, xmlContent = ServerToolkits.newStringUtf8(Arrays.copyOfRange(bytes, 20, 20 + xmlLength));
20 + xmlLength)); fromAppId = ServerToolkits.newStringUtf8(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length));
fromAppId = ServerToolkits.newStringUtf8(Arrays.copyOfRange(bytes,
20 + xmlLength, bytes.length));
} catch (Exception e) { } catch (Exception e) {
throw new WeixinException("-40008", "xml内容不合法:" + e.getMessage()); throw new RuntimeException("-40008,xml内容不合法:" + e.getMessage());
} }
// 校验appId是否一致 // 校验appId是否一致
if (appId != null && !fromAppId.trim().equals(appId)) { if (appId != null && !fromAppId.trim().equals(appId)) {
throw new WeixinException("-40005", "校验AppID失败,expect " + appId throw new RuntimeException("-40005,校验AppID失败,expect " + appId + ",but actual is " + fromAppId);
+ ",but actual is " + fromAppId);
} }
return xmlContent; return xmlContent;
} }

View File

@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.server.ext;
import java.util.Set; import java.util.Set;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.handler.WeixinMessageHandler;
import com.foxinmy.weixin4j.qy.suite.SuiteEventType; import com.foxinmy.weixin4j.qy.suite.SuiteEventType;
import com.foxinmy.weixin4j.qy.suite.SuiteMessage; import com.foxinmy.weixin4j.qy.suite.SuiteMessage;
@ -22,14 +21,12 @@ import com.foxinmy.weixin4j.response.WeixinResponse;
public class SuiteMessageHandler implements WeixinMessageHandler { public class SuiteMessageHandler implements WeixinMessageHandler {
@Override @Override
public boolean canHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) public boolean canHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) {
throws WeixinException {
return nodeNames.contains("suiteid"); return nodeNames.contains("suiteid");
} }
@Override @Override
public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) {
throws WeixinException {
SuiteMessage suiteMessage = null; // 转换为 SuiteMessage SuiteMessage suiteMessage = null; // 转换为 SuiteMessage
SuiteEventType eventType = suiteMessage.getFormatEventType(); SuiteEventType eventType = suiteMessage.getFormatEventType();
if (eventType == SuiteEventType.suite_ticket) { if (eventType == SuiteEventType.suite_ticket) {

View File

@ -1,13 +1,10 @@
package com.foxinmy.weixin4j.server.test; package com.foxinmy.weixin4j.server.test;
import io.netty.channel.ChannelHandlerContext;
import java.util.Set; import java.util.Set;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import com.foxinmy.weixin4j.dispatcher.BeanFactory; import com.foxinmy.weixin4j.dispatcher.BeanFactory;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.handler.DebugMessageHandler; import com.foxinmy.weixin4j.handler.DebugMessageHandler;
import com.foxinmy.weixin4j.handler.MessageHandlerAdapter; import com.foxinmy.weixin4j.handler.MessageHandlerAdapter;
import com.foxinmy.weixin4j.handler.MultipleMessageHandlerAdapter; 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.spring.SpringBeanFactory;
import com.foxinmy.weixin4j.startup.WeixinServerBootstrap; import com.foxinmy.weixin4j.startup.WeixinServerBootstrap;
import io.netty.channel.ChannelHandlerContext;
/** /**
* 服务启动测试类 * 服务启动测试类
* *
@ -44,12 +43,10 @@ public class MessageServerStartup {
/** /**
* 调试输出用户发来的消息 * 调试输出用户发来的消息
* *
* @throws WeixinException
*/ */
public void test1() throws WeixinException { public void test1() {
// 明文模式 // 明文模式
new WeixinServerBootstrap(token).addHandler(DebugMessageHandler.global) new WeixinServerBootstrap(token).addHandler(DebugMessageHandler.global).startup();
.startup();
// 密文模式 // 密文模式
// new WeixinServerBootstrap(weixinId, token, aesKey).addHandler( // new WeixinServerBootstrap(weixinId, token, aesKey).addHandler(
// DebugMessageHandler.global).startup(); // DebugMessageHandler.global).startup();
@ -58,96 +55,83 @@ public class MessageServerStartup {
/** /**
* 针对特定消息类型 * 针对特定消息类型
* *
* @throws WeixinException
*/ */
public void test2() throws WeixinException { public void test2() {
// 针对文本消息回复 // 针对文本消息回复
WeixinMessageHandler textMessageHandler = new MessageHandlerAdapter<TextMessage>() { WeixinMessageHandler textMessageHandler = new MessageHandlerAdapter<TextMessage>() {
@Override @Override
public WeixinResponse doHandle0(WeixinRequest request, public WeixinResponse doHandle0(WeixinRequest request, TextMessage message) {
TextMessage message) throws WeixinException {
return new TextResponse("HelloWorld!"); return new TextResponse("HelloWorld!");
} }
}; };
// 针对语音消息回复 // 针对语音消息回复
WeixinMessageHandler voiceMessageHandler = new MessageHandlerAdapter<VoiceMessage>() { WeixinMessageHandler voiceMessageHandler = new MessageHandlerAdapter<VoiceMessage>() {
@Override @Override
public WeixinResponse doHandle0(WeixinRequest request, public WeixinResponse doHandle0(WeixinRequest request, VoiceMessage message) {
VoiceMessage message) throws WeixinException {
return new TextResponse("HelloWorld!"); return new TextResponse("HelloWorld!");
} }
}; };
// 当消息类型为文本(text)或者语音时回复HelloWorld, 否则回复调试消息 // 当消息类型为文本(text)或者语音时回复HelloWorld, 否则回复调试消息
new WeixinServerBootstrap(weixinId, token, aesKey).addHandler( new WeixinServerBootstrap(weixinId, token, aesKey)
textMessageHandler, voiceMessageHandler, .addHandler(textMessageHandler, voiceMessageHandler, DebugMessageHandler.global).startup();
DebugMessageHandler.global).startup();
} }
/** /**
* 多种消息类型处理 * 多种消息类型处理
* *
* @throws WeixinException
*/ */
public void test3() throws WeixinException { public void test3() {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
MultipleMessageHandlerAdapter messageHandler = new MultipleMessageHandlerAdapter( MultipleMessageHandlerAdapter messageHandler = new MultipleMessageHandlerAdapter(ScanEventMessage.class,
ScanEventMessage.class, TextMessage.class) { TextMessage.class) {
@Override @Override
public WeixinResponse doHandle(WeixinRequest request, public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message, Set<String> nodeNames) {
WeixinMessage message, Set<String> nodeNames)
throws WeixinException {
return new TextResponse("处理了扫描和文字消息"); return new TextResponse("处理了扫描和文字消息");
} }
}; };
new WeixinServerBootstrap(token).addHandler(messageHandler, new WeixinServerBootstrap(token).addHandler(messageHandler, DebugMessageHandler.global).startup();
DebugMessageHandler.global).startup();
} }
/** /**
* 扫描包添加handler * 扫描包添加handler
* *
* @throws WeixinException * @
*/ */
public void test4() throws WeixinException { public void test4() {
// handler处理所在的包名(子包也会扫描) // handler处理所在的包名(子包也会扫描)
String packageToScan = "com.foxinmy.weixin4j.handler"; String packageToScan = "com.foxinmy.weixin4j.handler";
// handler默认使用 Class.newInstance // handler默认使用 Class.newInstance
// 方式实例化,如果handler中含有service等类需要注入,可以声明一个BeanFactory,如SpringBeanFactory // 方式实例化,如果handler中含有service等类需要注入,可以声明一个BeanFactory,如SpringBeanFactory
ApplicationContext applicationContext = null; // spring容器 ApplicationContext applicationContext = null; // spring容器
BeanFactory beanFactory = new SpringBeanFactory(applicationContext); BeanFactory beanFactory = new SpringBeanFactory(applicationContext);
new WeixinServerBootstrap(token).handlerPackagesToScan(packageToScan) new WeixinServerBootstrap(token).handlerPackagesToScan(packageToScan).openAlwaysResponse()
.openAlwaysResponse().resolveBeanFactory(beanFactory).startup(); .resolveBeanFactory(beanFactory).startup();
} }
/** /**
* 拦截器应用 * 拦截器应用
* *
* @throws WeixinException * @
*/ */
public void test5() throws WeixinException { public void test5() {
// 拦截所有请求 // 拦截所有请求
WeixinMessageInterceptor interceptor = new WeixinMessageInterceptor() { WeixinMessageInterceptor interceptor = new WeixinMessageInterceptor() {
@Override @Override
public boolean preHandle(ChannelHandlerContext context, public boolean preHandle(ChannelHandlerContext context, WeixinRequest request, WeixinMessage message,
WeixinRequest request, WeixinMessage message, WeixinMessageHandler handler) {
WeixinMessageHandler handler) throws WeixinException {
context.writeAndFlush(new TextResponse("所有消息被拦截了!")); context.writeAndFlush(new TextResponse("所有消息被拦截了!"));
return false; return false;
} }
@Override @Override
public void postHandle(ChannelHandlerContext context, public void postHandle(ChannelHandlerContext context, WeixinRequest request, WeixinResponse response,
WeixinRequest request, WeixinResponse response, WeixinMessage message, WeixinMessageHandler handler) {
WeixinMessage message, WeixinMessageHandler handler)
throws WeixinException {
System.err.println("preHandle返回为true,执行handler后"); System.err.println("preHandle返回为true,执行handler后");
} }
@Override @Override
public void afterCompletion(ChannelHandlerContext context, public void afterCompletion(ChannelHandlerContext context, WeixinRequest request, WeixinResponse response,
WeixinRequest request, WeixinResponse response, WeixinMessage message, WeixinMessageHandler handler, Exception exception) {
WeixinMessage message, WeixinMessageHandler handler,
Exception exception) throws WeixinException {
System.err.println("请求处理完毕"); System.err.println("请求处理完毕");
} }
@ -156,8 +140,7 @@ public class MessageServerStartup {
return 0; return 0;
} }
}; };
new WeixinServerBootstrap(token).addInterceptor(interceptor) new WeixinServerBootstrap(token).addInterceptor(interceptor).openAlwaysResponse().startup();
.openAlwaysResponse().startup();
} }
/** /**