weixin4j-server:实现消息处理器的泛型自动匹配

This commit is contained in:
jinyu 2015-05-16 18:36:16 +08:00
parent b6ec2485c9
commit 67d87a0a69
19 changed files with 456 additions and 208 deletions

View File

@ -284,3 +284,7 @@
* 2015-05-15 * 2015-05-15
+ **weixin4j-server**: 消息拦截器和处理器支持泛型 + **weixin4j-server**: 消息拦截器和处理器支持泛型
* 2015-05-16
+ **weixin4j-server**: 实现消息处理器的泛型自动匹配

View File

@ -32,4 +32,8 @@
* 2015-05-15 * 2015-05-15
+ **weixin4j-server**: 消息拦截器和处理器支持泛型 + 消息拦截器和处理器支持泛型
* 2015-05-16
+ 实现消息处理器的泛型自动匹配

View File

@ -37,23 +37,18 @@ weixin4j-server
public class MessageServerStartup{ public class MessageServerStartup{
public static void main(String[] args) { public static void main(String[] args) {
// 需要一个文本消息的handler // 针对文本消息回复
WeixinMessageHandler messageHandler = new WeixinMessageHandler() { WeixinMessageHandler messageHandler = new MessageHandlerAdapter<TextMessage>() {
@Override @Override
public WeixinResponse doHandle(WeixinRequest request, public WeixinResponse doHandle0(WeixinRequest request,
WeixinMessage message) throws WeixinException { TextMessage message) throws WeixinException {
return new TextResponse("HelloWorld!"); return new TextResponse("HelloWorld!");
}
@Override
public boolean canHandle(WeixinRequest request,
WeixinMessage message) {
return message.getMsgType().equals("text");
} }
}; };
// 当消息类型为文本(text)时回复「HelloWorld」, 否则回复调试消息 // 当消息类型为文本(text)时回复「HelloWorld」, 否则回复调试消息
new WeixinServerBootstrap("appid","开发者token","加密密钥").addHandler(messageHandler, new WeixinServerBootstrap(appid, token, aesKey).addHandler(
DebugMessageHandler.global).startup(); messageHandler, DebugMessageHandler.global).startup();
}
} }
} }
编写一个拦截器 编写一个拦截器
@ -63,22 +58,21 @@ weixin4j-server
WeixinMessageInterceptor interceptor = new MessageInterceptorAdapter() { WeixinMessageInterceptor interceptor = new MessageInterceptorAdapter() {
@Override @Override
public boolean preHandle(ChannelHandlerContext context, public boolean preHandle(ChannelHandlerContext context,
WeixinRequest request, WeixinMessage message, WeixinRequest request, Object message,
WeixinMessageHandler handler) throws WeixinException { WeixinMessageHandler handler) throws WeixinException {
context.write(new TextResponse("所有消息被拦截了!")); context.write(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) Object message, WeixinMessageHandler handler)
throws WeixinException { 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, WeixinMessage message, WeixinRequest request, Object message,
WeixinMessageHandler handler, WeixinException exception) WeixinMessageHandler handler, WeixinException exception)
throws WeixinException { throws WeixinException {
System.err.println("请求处理完毕"); System.err.println("请求处理完毕");

View File

@ -48,7 +48,7 @@ public class MessageHandlerExecutor {
return messageHandler; return messageHandler;
} }
public boolean applyPreHandle(WeixinRequest request, String message) public boolean applyPreHandle(WeixinRequest request, Object message)
throws WeixinException { throws WeixinException {
if (messageInterceptors != null) { if (messageInterceptors != null) {
for (int i = 0; i < messageInterceptors.length; i++) { for (int i = 0; i < messageInterceptors.length; i++) {
@ -65,7 +65,7 @@ public class MessageHandlerExecutor {
} }
public void applyPostHandle(WeixinRequest request, WeixinResponse response, public void applyPostHandle(WeixinRequest request, WeixinResponse response,
String message) throws WeixinException { Object message) throws WeixinException {
if (messageInterceptors == null) { if (messageInterceptors == null) {
return; return;
} }
@ -76,7 +76,7 @@ public class MessageHandlerExecutor {
} }
} }
public void triggerAfterCompletion(WeixinRequest request, String message, public void triggerAfterCompletion(WeixinRequest request, Object message,
WeixinException exception) throws WeixinException { WeixinException exception) throws WeixinException {
if (messageInterceptors == null) { if (messageInterceptors == null) {
return; return;

View File

@ -1,69 +0,0 @@
package com.foxinmy.weixin4j.dispatcher;
import java.io.ByteArrayInputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.request.WeixinMessage;
import com.foxinmy.weixin4j.util.Consts;
public abstract class WeixinMessageAdapter<M> {
/**
* 消息类集合
*/
private static final Map<Class<?>, Unmarshaller> unmarshallerMap;
static {
unmarshallerMap = new HashMap<Class<?>, Unmarshaller>();
}
@SuppressWarnings("unchecked")
protected M messageRead(String message) throws WeixinException {
try {
Class<?> clazz = resolveMessageClass();
Source source = new StreamSource(new ByteArrayInputStream(
message.getBytes(Consts.UTF_8)));
JAXBElement<?> jaxbElement = getUnmarshaller().unmarshal(source,
clazz);
return (M) jaxbElement.getValue();
} catch (JAXBException e) {
throw new WeixinException(e);
}
}
protected Unmarshaller getUnmarshaller() throws WeixinException {
Class<?> mineClass = resolveMessageClass();
Unmarshaller unmarshaller = unmarshallerMap.get(mineClass);
if (unmarshaller == null) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(mineClass);
unmarshaller = jaxbContext.createUnmarshaller();
unmarshallerMap.put(mineClass, unmarshaller);
} catch (JAXBException e) {
throw new WeixinException(e);
}
}
return unmarshaller;
}
protected Class<?> resolveMessageClass() {
Class<?> clazz = WeixinMessage.class;
Type type = getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
ParameterizedType ptype = ((ParameterizedType) type);
Type[] args = ptype.getActualTypeArguments();
clazz = (Class<?>) args[0];
}
return clazz;
}
}

View File

@ -4,21 +4,35 @@ import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.bean.BeanFactory; import com.foxinmy.weixin4j.bean.BeanFactory;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.handler.MessageHandlerAdapter;
import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.handler.WeixinMessageHandler;
import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor; import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.response.WeixinResponse;
import com.foxinmy.weixin4j.util.ClassUtil; import com.foxinmy.weixin4j.util.ClassUtil;
import com.foxinmy.weixin4j.util.Consts;
import com.foxinmy.weixin4j.util.HttpUtil; import com.foxinmy.weixin4j.util.HttpUtil;
import com.foxinmy.weixin4j.util.ReflectionUtil; import com.foxinmy.weixin4j.util.ReflectionUtil;
@ -60,14 +74,30 @@ public class WeixinMessageDispatcher {
*/ */
private BeanFactory beanFactory; private BeanFactory beanFactory;
/**
* 消息匹配
*/
private WeixinMessageMatcher messageMatcher;
/**
* 消息转换
*/
private Map<Class<?>, Unmarshaller> messageUnmarshaller;
public WeixinMessageDispatcher() { public WeixinMessageDispatcher() {
messageMatcher = new WeixinMessageMatcher();
messageUnmarshaller = new HashMap<Class<?>, Unmarshaller>();
} }
public void doDispatch(final ChannelHandlerContext context, public void doDispatch(final ChannelHandlerContext context,
final WeixinRequest request, final String message) final WeixinRequest request, final String uniqueKey)
throws WeixinException { throws WeixinException {
Class<?> targetClass = messageMatcher.find(uniqueKey);
Object message = request.getOriginalContent();
if (targetClass != null) {
message = messageRead(request.getOriginalContent(), targetClass);
}
MessageHandlerExecutor handlerExecutor = getHandlerExecutor(context, MessageHandlerExecutor handlerExecutor = getHandlerExecutor(context,
request, message); request, uniqueKey, message);
if (handlerExecutor == null if (handlerExecutor == null
|| handlerExecutor.getMessageHandler() == null) { || handlerExecutor.getMessageHandler() == null) {
noHandlerFound(context, request, message); noHandlerFound(context, request, message);
@ -93,23 +123,41 @@ public class WeixinMessageDispatcher {
} }
protected void noHandlerFound(ChannelHandlerContext ctx, protected void noHandlerFound(ChannelHandlerContext ctx,
WeixinRequest request, String message) { WeixinRequest request, Object message) {
ctx.writeAndFlush(HttpUtil.createHttpResponse(null, NOT_FOUND, null)) ctx.writeAndFlush(HttpUtil.createHttpResponse(null, NOT_FOUND, null))
.addListener(ChannelFutureListener.CLOSE); .addListener(ChannelFutureListener.CLOSE);
} }
protected MessageHandlerExecutor getHandlerExecutor( protected MessageHandlerExecutor getHandlerExecutor(
ChannelHandlerContext context, WeixinRequest request, String message) ChannelHandlerContext context, WeixinRequest request,
throws WeixinException { String uniqueKey, Object message) throws WeixinException {
WeixinMessageHandler messageHandler = null; WeixinMessageHandler messageHandler = null;
WeixinMessageHandler[] messageHandlers = getMessageHandlers(); WeixinMessageHandler[] messageHandlers = getMessageHandlers();
if (messageHandlers == null) { if (messageHandlers == null) {
return null; return null;
} }
for (WeixinMessageHandler handler : messageHandlers) { for (WeixinMessageHandler handler : messageHandlers) {
if (handler.canHandle(request, message)) { if (handler instanceof MessageHandlerAdapter) {
messageHandler = handler; Class<?> genericType = genericTypeRead(handler);
break; if (!messageMatcher.match(genericType)) {
message = messageRead(request.getOriginalContent(),
genericType);
messageMatcher.regist(uniqueKey, genericType);
}
if (genericType == message.getClass()
&& handler.canHandle(request, message)) {
messageHandler = handler;
break;
}
}
}
if (messageHandler == null) {
for (WeixinMessageHandler handler : messageHandlers) {
if (!(handler instanceof MessageHandlerAdapter)
&& handler.canHandle(request, message)) {
messageHandler = handler;
break;
}
} }
} }
return new MessageHandlerExecutor(context, messageHandler, return new MessageHandlerExecutor(context, messageHandler,
@ -205,6 +253,45 @@ public class WeixinMessageDispatcher {
return this.messageInterceptors; return this.messageInterceptors;
} }
protected Object messageRead(String message, Class<?> clazz)
throws WeixinException {
try {
Source source = new StreamSource(new ByteArrayInputStream(
message.getBytes(Consts.UTF_8)));
JAXBElement<?> jaxbElement = getUnmarshaller(clazz).unmarshal(
source, clazz);
return jaxbElement.getValue();
} catch (JAXBException e) {
throw new WeixinException(e);
}
}
protected Unmarshaller getUnmarshaller(Class<?> clazz)
throws WeixinException {
Unmarshaller unmarshaller = messageUnmarshaller.get(clazz);
if (unmarshaller == null) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
unmarshaller = jaxbContext.createUnmarshaller();
messageUnmarshaller.put(clazz, unmarshaller);
} catch (JAXBException e) {
throw new WeixinException(e);
}
}
return unmarshaller;
}
private Class<?> genericTypeRead(Object object) {
Class<?> clazz = null;
Type type = object.getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
ParameterizedType ptype = ((ParameterizedType) type);
Type[] args = ptype.getActualTypeArguments();
clazz = (Class<?>) args[0];
}
return clazz;
}
public void setMessageHandlerList( public void setMessageHandlerList(
List<WeixinMessageHandler> messageHandlerList) { List<WeixinMessageHandler> messageHandlerList) {
this.messageHandlerList = messageHandlerList; this.messageHandlerList = messageHandlerList;

View File

@ -0,0 +1,177 @@
package com.foxinmy.weixin4j.dispatcher;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.message.ImageMessage;
import com.foxinmy.weixin4j.message.LocationMessage;
import com.foxinmy.weixin4j.message.TextMessage;
import com.foxinmy.weixin4j.message.VideoMessage;
import com.foxinmy.weixin4j.message.VoiceMessage;
import com.foxinmy.weixin4j.message.event.LocationEventMessage;
import com.foxinmy.weixin4j.mp.event.KfCloseEventMessage;
import com.foxinmy.weixin4j.mp.event.KfCreateEventMessage;
import com.foxinmy.weixin4j.mp.event.KfSwitchEventMessage;
import com.foxinmy.weixin4j.mp.event.MassEventMessage;
import com.foxinmy.weixin4j.mp.event.ScanEventMessage;
import com.foxinmy.weixin4j.mp.event.TemplatesendjobfinishMessage;
import com.foxinmy.weixin4j.qy.event.BatchjobresultMessage;
import com.foxinmy.weixin4j.qy.event.EnterAgentEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
public class WeixinMessageMatcher {
private final Logger log = LoggerFactory.getLogger(getClass());
private final String MP_TAG = "mp";
private final String QY_TAG = "qy";
private final Map<String, Class<?>> key2ClassMap;
private final Map<Class<?>, String> class2KeyMap;
public WeixinMessageMatcher() {
key2ClassMap = new HashMap<String, Class<?>>();
class2KeyMap = new HashMap<Class<?>, String>();
init0();
init1();
init2();
init3();
log.info("detected message for events: {}", key2ClassMap.keySet());
}
private void init0() {
// /////////////////////////////////////////////////
/******************** 普通消息 ********************/
// /////////////////////////////////////////////////
String uniqueKey = MessageType.text.name();
Class<?> clazz = TextMessage.class;
regist(uniqueKey, clazz);
uniqueKey = MessageType.image.name();
clazz = ImageMessage.class;
regist(uniqueKey, clazz);
uniqueKey = MessageType.voice.name();
clazz = VoiceMessage.class;
regist(uniqueKey, clazz);
uniqueKey = MessageType.video.name();
clazz = VideoMessage.class;
regist(uniqueKey, clazz);
uniqueKey = MessageType.shortvideo.name();
regist(uniqueKey, clazz);
uniqueKey = MessageType.location.name();
clazz = LocationMessage.class;
regist(uniqueKey, clazz);
}
private void init1() {
// /////////////////////////////////////////////////
/******************** 事件消息 ********************/
// /////////////////////////////////////////////////
String uniqueKey;
Class<?> clazz;
for (EventType eventType : new EventType[] { EventType.subscribe,
EventType.unsubscribe }) {
uniqueKey = String.format("%s:%s", MessageType.event.name(),
eventType.name());
clazz = com.foxinmy.weixin4j.mp.event.ScribeEventMessage.class;
regist(String.format("%s:%s", MP_TAG, uniqueKey), clazz);
}
for (EventType eventType : new EventType[] { EventType.subscribe,
EventType.unsubscribe }) {
uniqueKey = String.format("%s:%s", MessageType.event.name(),
eventType.name());
clazz = com.foxinmy.weixin4j.qy.event.ScribeEventMessage.class;
regist(String.format("%s:%s", QY_TAG, uniqueKey), clazz);
}
uniqueKey = String.format("%s:%s", MessageType.event.name(),
EventType.location.name());
clazz = LocationEventMessage.class;
regist(uniqueKey, clazz);
for (EventType eventType : new EventType[] { EventType.click,
EventType.view }) {
uniqueKey = String.format("%s:%s", MessageType.event.name(),
eventType.name());
clazz = com.foxinmy.weixin4j.message.event.MenuEventMessage.class;
regist(uniqueKey, clazz);
}
for (EventType eventType : new EventType[] { EventType.scancode_push,
EventType.scancode_waitmsg }) {
uniqueKey = String.format("%s:%s", MessageType.event.name(),
eventType.name());
clazz = com.foxinmy.weixin4j.message.event.MenuScanEventMessage.class;
regist(uniqueKey, clazz);
}
for (EventType eventType : new EventType[] { EventType.pic_sysphoto,
EventType.pic_photo_or_album, EventType.pic_weixin }) {
uniqueKey = String.format("%s:%s", MessageType.event.name(),
eventType.name());
clazz = com.foxinmy.weixin4j.message.event.MenuPhotoEventMessage.class;
regist(uniqueKey, clazz);
}
uniqueKey = String.format("%s:%s", MessageType.event.name(),
EventType.location_select.name());
clazz = com.foxinmy.weixin4j.message.event.MenuLocationEventMessage.class;
regist(uniqueKey, clazz);
}
private void init2() {
// /////////////////////////////////////////////////
/******************** 公众平台事件消息 ********************/
// /////////////////////////////////////////////////
String uniqueKey = String.format("%s:%s:%s", MP_TAG,
MessageType.event.name(), EventType.scan.name());
Class<?> clazz = ScanEventMessage.class;
regist(uniqueKey, clazz);
uniqueKey = String.format("%s:%s:%s", MP_TAG, MessageType.event.name(),
EventType.masssendjobfinish.name());
clazz = MassEventMessage.class;
regist(uniqueKey, clazz);
uniqueKey = String.format("%s:%s:%s", MP_TAG, MessageType.event.name(),
EventType.templatesendjobfinish.name());
clazz = TemplatesendjobfinishMessage.class;
regist(uniqueKey, clazz);
uniqueKey = String.format("%s:%s:%s", MP_TAG, MessageType.event.name(),
EventType.kf_create_session.name());
clazz = KfCreateEventMessage.class;
regist(uniqueKey, clazz);
uniqueKey = String.format("%s:%s:%s", MP_TAG, MessageType.event.name(),
EventType.kf_close_session.name());
clazz = KfCloseEventMessage.class;
regist(uniqueKey, clazz);
uniqueKey = String.format("%s:%s:%s", MP_TAG, MessageType.event.name(),
EventType.kf_switch_session.name());
clazz = KfSwitchEventMessage.class;
regist(uniqueKey, clazz);
}
private void init3() {
// /////////////////////////////////////////////////
/******************** 企业号事件消息 ********************/
// /////////////////////////////////////////////////
String uniqueKey = String.format("%s:%s:%s", QY_TAG,
MessageType.event.name(), EventType.batch_job_result.name());
Class<?> clazz = BatchjobresultMessage.class;
regist(uniqueKey, clazz);
uniqueKey = String.format("%s:%s:%s", QY_TAG, MessageType.event.name(),
EventType.enter_agent.name());
clazz = EnterAgentEventMessage.class;
regist(uniqueKey, clazz);
}
public void regist(String uniqueKey, Class<?> clazz) {
key2ClassMap.put(uniqueKey, clazz);
class2KeyMap.put(clazz, uniqueKey);
}
public boolean match(Object keyOrClass) {
return key2ClassMap.containsKey(keyOrClass)
|| class2KeyMap.containsKey(keyOrClass);
}
public Class<?> find(String uniqueKey) {
return key2ClassMap.get(uniqueKey);
}
}

View File

@ -14,13 +14,13 @@ public class BlankMessageHandler implements WeixinMessageHandler {
} }
@Override @Override
public boolean canHandle(WeixinRequest request, String message) public boolean canHandle(WeixinRequest request, Object message)
throws WeixinException { throws WeixinException {
return true; return true;
} }
@Override @Override
public WeixinResponse doHandle(WeixinRequest request, String message) public WeixinResponse doHandle(WeixinRequest request, Object message)
throws WeixinException { throws WeixinException {
return BlankResponse.global; return BlankResponse.global;
} }

View File

@ -14,14 +14,14 @@ public class DebugMessageHandler implements WeixinMessageHandler {
} }
@Override @Override
public boolean canHandle(WeixinRequest request, String message) public boolean canHandle(WeixinRequest request, Object message)
throws WeixinException { throws WeixinException {
return true; return true;
} }
@Override @Override
public WeixinResponse doHandle(WeixinRequest request, String message) public WeixinResponse doHandle(WeixinRequest request, Object message)
throws WeixinException { throws WeixinException {
return new TextResponse(message); return new TextResponse(message.toString());
} }
} }

View File

@ -1,32 +1,30 @@
package com.foxinmy.weixin4j.handler; package com.foxinmy.weixin4j.handler;
import com.foxinmy.weixin4j.dispatcher.WeixinMessageAdapter;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.response.WeixinResponse;
public abstract class MessageHandlerAdapter<M> extends WeixinMessageAdapter<M> @SuppressWarnings("unchecked")
implements WeixinMessageHandler { public abstract class MessageHandlerAdapter<M> implements WeixinMessageHandler {
private M message;
@Override @Override
public boolean canHandle(WeixinRequest request, String message) public boolean canHandle(WeixinRequest request, Object message)
throws WeixinException { throws WeixinException {
this.message = super.messageRead(message); return canHandle0(request, (M) message);
return canHandle0(request, message, this.message);
} }
public abstract boolean canHandle0(WeixinRequest request, String message, public boolean canHandle0(WeixinRequest request, M message)
M m) throws WeixinException; throws WeixinException {
return true;
}
@Override @Override
public WeixinResponse doHandle(WeixinRequest request, String message) public WeixinResponse doHandle(WeixinRequest request, Object message)
throws WeixinException { throws WeixinException {
return doHandle0(request, message, this.message); return doHandle0(request, (M) message);
} }
public abstract WeixinResponse doHandle0(WeixinRequest request, public abstract WeixinResponse doHandle0(WeixinRequest request, M message)
String message, M m) throws WeixinException; throws WeixinException;
} }

View File

@ -24,7 +24,7 @@ public interface WeixinMessageHandler {
* 微信消息 * 微信消息
* @return * @return
*/ */
public boolean canHandle(WeixinRequest request, String message) public boolean canHandle(WeixinRequest request, Object message)
throws WeixinException; throws WeixinException;
/** /**
@ -36,6 +36,6 @@ public interface WeixinMessageHandler {
* 微信消息 * 微信消息
* @return * @return
*/ */
public WeixinResponse doHandle(WeixinRequest request, String message) public WeixinResponse doHandle(WeixinRequest request, Object message)
throws WeixinException; throws WeixinException;
} }

View File

@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.interceptor;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import com.foxinmy.weixin4j.dispatcher.WeixinMessageAdapter;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.handler.WeixinMessageHandler;
import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.request.WeixinRequest;
@ -17,45 +16,26 @@ import com.foxinmy.weixin4j.response.WeixinResponse;
* @since JDK 1.7 * @since JDK 1.7
* @see * @see
*/ */
public abstract class MessageInterceptorAdapter<M> extends public abstract class MessageInterceptorAdapter implements
WeixinMessageAdapter<M> implements WeixinMessageInterceptor { WeixinMessageInterceptor {
private M message;
@Override @Override
public boolean preHandle(ChannelHandlerContext context, public boolean preHandle(ChannelHandlerContext context,
WeixinRequest request, final String message, WeixinRequest request, Object message, WeixinMessageHandler handler)
WeixinMessageHandler handler) throws WeixinException { throws WeixinException {
this.message = super.messageRead(message); return true;
return preHandle0(context, request, this.message, handler);
} }
public abstract boolean preHandle0(ChannelHandlerContext context,
WeixinRequest request, M message, WeixinMessageHandler handler)
throws WeixinException;
@Override @Override
public void postHandle(ChannelHandlerContext context, public void postHandle(ChannelHandlerContext context,
WeixinRequest request, WeixinResponse response, String message, WeixinRequest request, WeixinResponse response, Object message,
WeixinMessageHandler handler) throws WeixinException { WeixinMessageHandler handler) throws WeixinException {
postHandle0(context, request, response, message, this.message, handler);
} }
public abstract void postHandle0(ChannelHandlerContext context,
WeixinRequest request, WeixinResponse response, String message,
M m, WeixinMessageHandler handler) throws WeixinException;
@Override @Override
public void afterCompletion(ChannelHandlerContext context, public void afterCompletion(ChannelHandlerContext context,
WeixinRequest request, String message, WeixinRequest request, Object message,
WeixinMessageHandler handler, WeixinException exception) WeixinMessageHandler handler, WeixinException exception)
throws WeixinException { throws WeixinException {
afterCompletion0(context, request, message, this.message, handler,
exception);
} }
public abstract void afterCompletion0(ChannelHandlerContext context,
WeixinRequest request, String message, M m,
WeixinMessageHandler handler, WeixinException exception)
throws WeixinException;
} }

View File

@ -33,7 +33,7 @@ public interface WeixinMessageInterceptor {
* @throws WeixinException * @throws WeixinException
*/ */
boolean preHandle(ChannelHandlerContext context, WeixinRequest request, boolean preHandle(ChannelHandlerContext context, WeixinRequest request,
String message, WeixinMessageHandler handler) Object message, WeixinMessageHandler handler)
throws WeixinException; throws WeixinException;
/** /**
@ -52,7 +52,7 @@ public interface WeixinMessageInterceptor {
* @throws WeixinException * @throws WeixinException
*/ */
void postHandle(ChannelHandlerContext context, WeixinRequest request, void postHandle(ChannelHandlerContext context, WeixinRequest request,
WeixinResponse response, String message, WeixinResponse response, Object message,
WeixinMessageHandler handler) throws WeixinException; WeixinMessageHandler handler) throws WeixinException;
/** /**
@ -71,6 +71,6 @@ public interface WeixinMessageInterceptor {
* @throws WeixinException * @throws WeixinException
*/ */
void afterCompletion(ChannelHandlerContext context, WeixinRequest request, void afterCompletion(ChannelHandlerContext context, WeixinRequest request,
String message, WeixinMessageHandler handler, Object message, WeixinMessageHandler handler,
WeixinException exception) throws WeixinException; WeixinException exception) throws WeixinException;
} }

View File

@ -8,28 +8,19 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpMethod;
import java.io.ByteArrayInputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.bean.AesToken; import com.foxinmy.weixin4j.bean.AesToken;
import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher; import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.request.WeixinMessage;
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.Consts; import com.foxinmy.weixin4j.util.Consts;
import com.foxinmy.weixin4j.util.HttpUtil; import com.foxinmy.weixin4j.util.HttpUtil;
import com.foxinmy.weixin4j.util.MessageUtil; import com.foxinmy.weixin4j.util.MessageUtil;
import com.foxinmy.weixin4j.util.StringUtil; import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.xml.CruxMessageHandler;
/** /**
* 微信请求处理类 * 微信请求处理类
@ -108,27 +99,17 @@ public class WeixinRequestHandler extends
.addListener(ChannelFutureListener.CLOSE); .addListener(ChannelFutureListener.CLOSE);
return; return;
} }
final String message = request.getOriginalContent(); CruxMessageHandler messageHandler = CruxMessageHandler.parser(request
WeixinMessage weixinMessage; .getOriginalContent());
try {
Unmarshaller unmarshaller = JAXBContext.newInstance(
WeixinMessage.class).createUnmarshaller();
Source source = new StreamSource(new ByteArrayInputStream(
message.getBytes()));
JAXBElement<WeixinMessage> jaxbElement = unmarshaller.unmarshal(
source, WeixinMessage.class);
weixinMessage = jaxbElement.getValue();
} catch (JAXBException e) {
throw new WeixinException(e);
}
ctx.channel().attr(Consts.ENCRYPTTYPE_KEY) ctx.channel().attr(Consts.ENCRYPTTYPE_KEY)
.set(request.getEncryptType()); .set(request.getEncryptType());
ctx.channel().attr(Consts.USEROPENID_KEY) ctx.channel().attr(Consts.USEROPENID_KEY)
.set(weixinMessage.getFromUserName()); .set(messageHandler.getFromUserName());
if (StringUtil.isBlank(aesToken.getAppid())) { if (StringUtil.isBlank(aesToken.getAppid())) {
ctx.channel().attr(Consts.ACCOUNTOPENID_KEY) ctx.channel().attr(Consts.ACCOUNTOPENID_KEY)
.set(weixinMessage.getToUserName()); .set(messageHandler.getToUserName());
} }
messageDispatcher.doDispatch(ctx, request, message); messageDispatcher.doDispatch(ctx, request,
messageHandler.getUniqueKey());
} }
} }

View File

@ -26,57 +26,56 @@ public enum EventType {
* @see com.foxinmy.weixin4j.message.event.LocationEventMessage * @see com.foxinmy.weixin4j.message.event.LocationEventMessage
*/ */
location, location,
/**
* 菜单扫描事件
*
* @see com.foxinmy.weixin4j.message.event.menu.MenuScanEventMessage
*/
scancode_push,
/** /**
* 菜单点击关键字事件 * 菜单点击关键字事件
* *
* @see com.foxinmy.weixin4j.message.event.menu.MenuEventMessage * @see com.foxinmy.weixin4j.message.event.MenuEventMessage
*/ */
view, view,
/** /**
* 菜单点击链接事件 * 菜单点击链接事件
* *
* @see com.foxinmy.weixin4j.message.event.menu.MenuEventMessage * @see com.foxinmy.weixin4j.message.event.MenuEventMessage
*/ */
click, click,
/**
* 菜单扫描事件
*
* @see com.foxinmy.weixin4j.message.event.MenuScanEventMessage
*/
scancode_push,
/** /**
* 菜单扫描并调出等待界面事件 * 菜单扫描并调出等待界面事件
* *
* @see com.foxinmy.weixin4j.message.event.menu.MenuScanEventMessage * @see com.foxinmy.weixin4j.message.event.MenuScanEventMessage
*/ */
scancode_waitmsg, scancode_waitmsg,
/** /**
* 菜单弹出拍照事件 * 菜单弹出拍照事件
* *
* @see com.foxinmy.weixin4j.message.event.menu.MenuPhotoEventMessage * @see com.foxinmy.weixin4j.message.event.MenuPhotoEventMessage
*/ */
pic_sysphoto, pic_sysphoto,
/** /**
* 菜单弹出发图事件 * 菜单弹出发图事件
* *
* @see com.foxinmy.weixin4j.message.event.menu.MenuPhotoEventMessage * @see com.foxinmy.weixin4j.message.event.MenuPhotoEventMessage
*/ */
pic_photo_or_album, pic_photo_or_album,
/** /**
* 菜单弹出发图事件 * 菜单弹出发图事件
* *
* @see com.foxinmy.weixin4j.message.event.menu.MenuPhotoEventMessage * @see com.foxinmy.weixin4j.message.event.MenuPhotoEventMessage
*/ */
pic_weixin, pic_weixin,
/** /**
* 菜单发送地理位置事件 * 菜单发送地理位置事件
* *
* @see com.foxinmy.weixin4j.message.event.menu.MenuLocationEventMessage * @see com.foxinmy.weixin4j.message.event.MenuLocationEventMessage
*/ */
location_select, location_select,
// ------------------------------公众平台特有------------------------------ // ------------------------------公众平台特有------------------------------
//
/** /**
* 二维码扫描事件 * 二维码扫描事件
@ -114,6 +113,8 @@ public enum EventType {
* @see com.foxinmy.weixin4j.mp.event.KfSwitchEventMessage * @see com.foxinmy.weixin4j.mp.event.KfSwitchEventMessage
*/ */
kf_switch_session, kf_switch_session,
// ------------------------------企业号特有------------------------------
/** /**
* 异步任务完成事件 * 异步任务完成事件
* *

View File

@ -52,8 +52,7 @@ public final class ClassUtil {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
throw new UnsupportedOperationException(String.format( return null;
"unknow protocol:", protocol));
} }
/** /**

View File

@ -0,0 +1,95 @@
package com.foxinmy.weixin4j.xml;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
import com.foxinmy.weixin4j.type.MessageType;
import com.foxinmy.weixin4j.util.Consts;
import com.foxinmy.weixin4j.util.StringUtil;
public class CruxMessageHandler extends DefaultHandler {
private String fromUserName;
private String toUserName;
private String msgType;
private String eventType;
private String agentId;
private String content;
@Override
public void startDocument() throws SAXException {
fromUserName = null;
toUserName = null;
msgType = null;
eventType = null;
agentId = null;
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if (localName.equalsIgnoreCase("fromUserName")) {
fromUserName = content;
} else if (localName.equalsIgnoreCase("toUserName")) {
toUserName = content;
} else if (localName.equalsIgnoreCase("msgType")) {
msgType = content.toLowerCase();
} else if (localName.equalsIgnoreCase("event")) {
eventType = content.toLowerCase();
} else if (localName.equalsIgnoreCase("agentId")) {
agentId = content;
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
this.content = new String(ch, start, length);
}
public String getUniqueKey() {
StringBuilder uniqueKey = new StringBuilder();
uniqueKey.append(msgType);
if (msgType.equals(MessageType.event.name())) {
if (StringUtil.isBlank(agentId)) {
uniqueKey.insert(0, "mp:");
} else {
uniqueKey.insert(0, "qy:");
}
uniqueKey.append(":").append(eventType);
}
return uniqueKey.toString();
}
public String getFromUserName() {
return fromUserName;
}
public String getToUserName() {
return toUserName;
}
private static CruxMessageHandler global = new CruxMessageHandler();
public static CruxMessageHandler parser(String xmlContent)
throws RuntimeException {
try {
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
xmlReader.setContentHandler(global);
xmlReader.parse(new InputSource(new ByteArrayInputStream(xmlContent
.getBytes(Consts.UTF_8))));
} catch (IOException e) {
throw new RuntimeException(e);
} catch (SAXException e) {
throw new RuntimeException(e);
}
return global;
}
}

View File

@ -15,6 +15,7 @@ import com.foxinmy.weixin4j.util.Consts;
public class EncryptMessageHandler extends DefaultHandler { public class EncryptMessageHandler extends DefaultHandler {
private String encryptContent; private String encryptContent;
private String content;
@Override @Override
public void startDocument() throws SAXException { public void startDocument() throws SAXException {
@ -24,28 +25,30 @@ public class EncryptMessageHandler extends DefaultHandler {
@Override @Override
public void startElement(String uri, String localName, String qName, public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException { Attributes attributes) throws SAXException {
if (qName.equalsIgnoreCase("encrypt")) {
return;
}
} }
@Override @Override
public void endElement(String uri, String localName, String qName) public void endElement(String uri, String localName, String qName)
throws SAXException { throws SAXException {
if (localName.equalsIgnoreCase("encrypt")) {
encryptContent = content;
}
} }
@Override @Override
public void characters(char[] ch, int start, int length) public void characters(char[] ch, int start, int length)
throws SAXException { throws SAXException {
this.encryptContent = new String(ch, start, length); this.content = new String(ch, start, length);
} }
public String getEncryptContent() { public String getEncryptContent() {
return encryptContent; return encryptContent;
} }
private final static EncryptMessageHandler messageHandler = new EncryptMessageHandler();
public static String parser(String xmlContent) throws RuntimeException { public static String parser(String xmlContent) throws RuntimeException {
EncryptMessageHandler messageHandler = new EncryptMessageHandler();
try { try {
XMLReader xmlReader = XMLReaderFactory.createXMLReader(); XMLReader xmlReader = XMLReaderFactory.createXMLReader();
xmlReader.setContentHandler(messageHandler); xmlReader.setContentHandler(messageHandler);

View File

@ -57,17 +57,11 @@ public class MessageServerStartup {
* @throws WeixinException * @throws WeixinException
*/ */
public void test3() throws WeixinException { public void test3() throws WeixinException {
// 文本消息回复 // 针对文本消息回复
WeixinMessageHandler messageHandler = new MessageHandlerAdapter<TextMessage>() { WeixinMessageHandler messageHandler = new MessageHandlerAdapter<TextMessage>() {
@Override
public boolean canHandle0(WeixinRequest request, String message,
TextMessage m) throws WeixinException {
return true;
}
@Override @Override
public WeixinResponse doHandle0(WeixinRequest request, public WeixinResponse doHandle0(WeixinRequest request,
String message, TextMessage m) throws WeixinException { TextMessage message) throws WeixinException {
return new TextResponse("HelloWorld!"); return new TextResponse("HelloWorld!");
} }
}; };
@ -88,7 +82,7 @@ public class MessageServerStartup {
WeixinMessageInterceptor interceptor = new WeixinMessageInterceptor() { WeixinMessageInterceptor interceptor = new WeixinMessageInterceptor() {
@Override @Override
public boolean preHandle(ChannelHandlerContext context, public boolean preHandle(ChannelHandlerContext context,
WeixinRequest request, String message, WeixinRequest request, Object message,
WeixinMessageHandler handler) throws WeixinException { WeixinMessageHandler handler) throws WeixinException {
context.writeAndFlush(new TextResponse("所有消息被拦截了!")); context.writeAndFlush(new TextResponse("所有消息被拦截了!"));
return false; return false;
@ -97,14 +91,14 @@ public class MessageServerStartup {
@Override @Override
public void postHandle(ChannelHandlerContext context, public void postHandle(ChannelHandlerContext context,
WeixinRequest request, WeixinResponse response, WeixinRequest request, WeixinResponse response,
String message, WeixinMessageHandler handler) Object message, WeixinMessageHandler handler)
throws WeixinException { 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, String message, WeixinRequest request, Object message,
WeixinMessageHandler handler, WeixinException exception) WeixinMessageHandler handler, WeixinException exception)
throws WeixinException { throws WeixinException {
System.err.println("请求处理完毕"); System.err.println("请求处理完毕");
@ -115,6 +109,6 @@ public class MessageServerStartup {
} }
public static void main(String[] args) throws WeixinException { public static void main(String[] args) throws WeixinException {
new MessageServerStartup().test1(); new MessageServerStartup().test5();
} }
} }