weixin4j-server:实现消息处理器的泛型自动匹配
This commit is contained in:
parent
b6ec2485c9
commit
67d87a0a69
@ -284,3 +284,7 @@
|
||||
* 2015-05-15
|
||||
|
||||
+ **weixin4j-server**: 消息拦截器和处理器支持泛型
|
||||
|
||||
* 2015-05-16
|
||||
|
||||
+ **weixin4j-server**: 实现消息处理器的泛型自动匹配
|
||||
|
||||
@ -32,4 +32,8 @@
|
||||
|
||||
* 2015-05-15
|
||||
|
||||
+ **weixin4j-server**: 消息拦截器和处理器支持泛型
|
||||
+ 消息拦截器和处理器支持泛型
|
||||
|
||||
* 2015-05-16
|
||||
|
||||
+ 实现消息处理器的泛型自动匹配
|
||||
@ -37,23 +37,18 @@ weixin4j-server
|
||||
|
||||
public class MessageServerStartup{
|
||||
public static void main(String[] args) {
|
||||
// 需要一个文本消息的handler
|
||||
WeixinMessageHandler messageHandler = new WeixinMessageHandler() {
|
||||
// 针对文本消息回复
|
||||
WeixinMessageHandler messageHandler = new MessageHandlerAdapter<TextMessage>() {
|
||||
@Override
|
||||
public WeixinResponse doHandle(WeixinRequest request,
|
||||
WeixinMessage message) throws WeixinException {
|
||||
public WeixinResponse doHandle0(WeixinRequest request,
|
||||
TextMessage message) throws WeixinException {
|
||||
return new TextResponse("HelloWorld!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(WeixinRequest request,
|
||||
WeixinMessage message) {
|
||||
return message.getMsgType().equals("text");
|
||||
}
|
||||
};
|
||||
// 当消息类型为文本(text)时回复「HelloWorld」, 否则回复调试消息
|
||||
new WeixinServerBootstrap("appid","开发者token","加密密钥").addHandler(messageHandler,
|
||||
DebugMessageHandler.global).startup();
|
||||
new WeixinServerBootstrap(appid, token, aesKey).addHandler(
|
||||
messageHandler, DebugMessageHandler.global).startup();
|
||||
}
|
||||
}
|
||||
}
|
||||
编写一个拦截器
|
||||
@ -63,22 +58,21 @@ weixin4j-server
|
||||
WeixinMessageInterceptor interceptor = new MessageInterceptorAdapter() {
|
||||
@Override
|
||||
public boolean preHandle(ChannelHandlerContext context,
|
||||
WeixinRequest request, WeixinMessage message,
|
||||
WeixinRequest request, Object message,
|
||||
WeixinMessageHandler handler) throws WeixinException {
|
||||
context.write(new TextResponse("所有消息被拦截了!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postHandle(ChannelHandlerContext context,
|
||||
WeixinRequest request, WeixinResponse response,
|
||||
WeixinMessage message, WeixinMessageHandler handler)
|
||||
Object message, WeixinMessageHandler handler)
|
||||
throws WeixinException {
|
||||
System.err.println("preHandle返回为true,执行handler后");
|
||||
}
|
||||
@Override
|
||||
public void afterCompletion(ChannelHandlerContext context,
|
||||
WeixinRequest request, WeixinMessage message,
|
||||
WeixinRequest request, Object message,
|
||||
WeixinMessageHandler handler, WeixinException exception)
|
||||
throws WeixinException {
|
||||
System.err.println("请求处理完毕");
|
||||
|
||||
@ -48,7 +48,7 @@ public class MessageHandlerExecutor {
|
||||
return messageHandler;
|
||||
}
|
||||
|
||||
public boolean applyPreHandle(WeixinRequest request, String message)
|
||||
public boolean applyPreHandle(WeixinRequest request, Object message)
|
||||
throws WeixinException {
|
||||
if (messageInterceptors != null) {
|
||||
for (int i = 0; i < messageInterceptors.length; i++) {
|
||||
@ -65,7 +65,7 @@ public class MessageHandlerExecutor {
|
||||
}
|
||||
|
||||
public void applyPostHandle(WeixinRequest request, WeixinResponse response,
|
||||
String message) throws WeixinException {
|
||||
Object message) throws WeixinException {
|
||||
if (messageInterceptors == null) {
|
||||
return;
|
||||
}
|
||||
@ -76,7 +76,7 @@ public class MessageHandlerExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
public void triggerAfterCompletion(WeixinRequest request, String message,
|
||||
public void triggerAfterCompletion(WeixinRequest request, Object message,
|
||||
WeixinException exception) throws WeixinException {
|
||||
if (messageInterceptors == null) {
|
||||
return;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -4,21 +4,35 @@ import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.foxinmy.weixin4j.bean.BeanFactory;
|
||||
import com.foxinmy.weixin4j.exception.WeixinException;
|
||||
import com.foxinmy.weixin4j.handler.MessageHandlerAdapter;
|
||||
import com.foxinmy.weixin4j.handler.WeixinMessageHandler;
|
||||
import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor;
|
||||
import com.foxinmy.weixin4j.request.WeixinRequest;
|
||||
import com.foxinmy.weixin4j.response.WeixinResponse;
|
||||
import com.foxinmy.weixin4j.util.ClassUtil;
|
||||
import com.foxinmy.weixin4j.util.Consts;
|
||||
import com.foxinmy.weixin4j.util.HttpUtil;
|
||||
import com.foxinmy.weixin4j.util.ReflectionUtil;
|
||||
|
||||
@ -60,14 +74,30 @@ public class WeixinMessageDispatcher {
|
||||
*/
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* 消息匹配
|
||||
*/
|
||||
private WeixinMessageMatcher messageMatcher;
|
||||
/**
|
||||
* 消息转换
|
||||
*/
|
||||
private Map<Class<?>, Unmarshaller> messageUnmarshaller;
|
||||
|
||||
public WeixinMessageDispatcher() {
|
||||
messageMatcher = new WeixinMessageMatcher();
|
||||
messageUnmarshaller = new HashMap<Class<?>, Unmarshaller>();
|
||||
}
|
||||
|
||||
public void doDispatch(final ChannelHandlerContext context,
|
||||
final WeixinRequest request, final String message)
|
||||
final WeixinRequest request, final String uniqueKey)
|
||||
throws WeixinException {
|
||||
Class<?> targetClass = messageMatcher.find(uniqueKey);
|
||||
Object message = request.getOriginalContent();
|
||||
if (targetClass != null) {
|
||||
message = messageRead(request.getOriginalContent(), targetClass);
|
||||
}
|
||||
MessageHandlerExecutor handlerExecutor = getHandlerExecutor(context,
|
||||
request, message);
|
||||
request, uniqueKey, message);
|
||||
if (handlerExecutor == null
|
||||
|| handlerExecutor.getMessageHandler() == null) {
|
||||
noHandlerFound(context, request, message);
|
||||
@ -93,25 +123,43 @@ public class WeixinMessageDispatcher {
|
||||
}
|
||||
|
||||
protected void noHandlerFound(ChannelHandlerContext ctx,
|
||||
WeixinRequest request, String message) {
|
||||
WeixinRequest request, Object message) {
|
||||
ctx.writeAndFlush(HttpUtil.createHttpResponse(null, NOT_FOUND, null))
|
||||
.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
|
||||
protected MessageHandlerExecutor getHandlerExecutor(
|
||||
ChannelHandlerContext context, WeixinRequest request, String message)
|
||||
throws WeixinException {
|
||||
ChannelHandlerContext context, WeixinRequest request,
|
||||
String uniqueKey, Object message) throws WeixinException {
|
||||
WeixinMessageHandler messageHandler = null;
|
||||
WeixinMessageHandler[] messageHandlers = getMessageHandlers();
|
||||
if (messageHandlers == null) {
|
||||
return null;
|
||||
}
|
||||
for (WeixinMessageHandler handler : messageHandlers) {
|
||||
if (handler.canHandle(request, message)) {
|
||||
if (handler instanceof MessageHandlerAdapter) {
|
||||
Class<?> genericType = genericTypeRead(handler);
|
||||
if (!messageMatcher.match(genericType)) {
|
||||
message = messageRead(request.getOriginalContent(),
|
||||
genericType);
|
||||
messageMatcher.regist(uniqueKey, genericType);
|
||||
}
|
||||
if (genericType == message.getClass()
|
||||
&& handler.canHandle(request, message)) {
|
||||
messageHandler = handler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (messageHandler == null) {
|
||||
for (WeixinMessageHandler handler : messageHandlers) {
|
||||
if (!(handler instanceof MessageHandlerAdapter)
|
||||
&& handler.canHandle(request, message)) {
|
||||
messageHandler = handler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new MessageHandlerExecutor(context, messageHandler,
|
||||
getMessageInterceptors());
|
||||
}
|
||||
@ -205,6 +253,45 @@ public class WeixinMessageDispatcher {
|
||||
return this.messageInterceptors;
|
||||
}
|
||||
|
||||
protected Object messageRead(String message, Class<?> clazz)
|
||||
throws WeixinException {
|
||||
try {
|
||||
Source source = new StreamSource(new ByteArrayInputStream(
|
||||
message.getBytes(Consts.UTF_8)));
|
||||
JAXBElement<?> jaxbElement = getUnmarshaller(clazz).unmarshal(
|
||||
source, clazz);
|
||||
return jaxbElement.getValue();
|
||||
} catch (JAXBException e) {
|
||||
throw new WeixinException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Unmarshaller getUnmarshaller(Class<?> clazz)
|
||||
throws WeixinException {
|
||||
Unmarshaller unmarshaller = messageUnmarshaller.get(clazz);
|
||||
if (unmarshaller == null) {
|
||||
try {
|
||||
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
|
||||
unmarshaller = jaxbContext.createUnmarshaller();
|
||||
messageUnmarshaller.put(clazz, unmarshaller);
|
||||
} catch (JAXBException e) {
|
||||
throw new WeixinException(e);
|
||||
}
|
||||
}
|
||||
return unmarshaller;
|
||||
}
|
||||
|
||||
private Class<?> genericTypeRead(Object object) {
|
||||
Class<?> clazz = null;
|
||||
Type type = object.getClass().getGenericSuperclass();
|
||||
if (type instanceof ParameterizedType) {
|
||||
ParameterizedType ptype = ((ParameterizedType) type);
|
||||
Type[] args = ptype.getActualTypeArguments();
|
||||
clazz = (Class<?>) args[0];
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public void setMessageHandlerList(
|
||||
List<WeixinMessageHandler> messageHandlerList) {
|
||||
this.messageHandlerList = messageHandlerList;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -14,13 +14,13 @@ public class BlankMessageHandler implements WeixinMessageHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(WeixinRequest request, String message)
|
||||
public boolean canHandle(WeixinRequest request, Object message)
|
||||
throws WeixinException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WeixinResponse doHandle(WeixinRequest request, String message)
|
||||
public WeixinResponse doHandle(WeixinRequest request, Object message)
|
||||
throws WeixinException {
|
||||
return BlankResponse.global;
|
||||
}
|
||||
|
||||
@ -14,14 +14,14 @@ public class DebugMessageHandler implements WeixinMessageHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(WeixinRequest request, String message)
|
||||
public boolean canHandle(WeixinRequest request, Object message)
|
||||
throws WeixinException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WeixinResponse doHandle(WeixinRequest request, String message)
|
||||
public WeixinResponse doHandle(WeixinRequest request, Object message)
|
||||
throws WeixinException {
|
||||
return new TextResponse(message);
|
||||
return new TextResponse(message.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,32 +1,30 @@
|
||||
package com.foxinmy.weixin4j.handler;
|
||||
|
||||
import com.foxinmy.weixin4j.dispatcher.WeixinMessageAdapter;
|
||||
import com.foxinmy.weixin4j.exception.WeixinException;
|
||||
import com.foxinmy.weixin4j.request.WeixinRequest;
|
||||
import com.foxinmy.weixin4j.response.WeixinResponse;
|
||||
|
||||
public abstract class MessageHandlerAdapter<M> extends WeixinMessageAdapter<M>
|
||||
implements WeixinMessageHandler {
|
||||
|
||||
private M message;
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract class MessageHandlerAdapter<M> implements WeixinMessageHandler {
|
||||
|
||||
@Override
|
||||
public boolean canHandle(WeixinRequest request, String message)
|
||||
public boolean canHandle(WeixinRequest request, Object message)
|
||||
throws WeixinException {
|
||||
this.message = super.messageRead(message);
|
||||
return canHandle0(request, message, this.message);
|
||||
return canHandle0(request, (M) message);
|
||||
}
|
||||
|
||||
public abstract boolean canHandle0(WeixinRequest request, String message,
|
||||
M m) throws WeixinException;
|
||||
public boolean canHandle0(WeixinRequest request, M message)
|
||||
throws WeixinException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WeixinResponse doHandle(WeixinRequest request, String message)
|
||||
public WeixinResponse doHandle(WeixinRequest request, Object message)
|
||||
throws WeixinException {
|
||||
return doHandle0(request, message, this.message);
|
||||
return doHandle0(request, (M) message);
|
||||
}
|
||||
|
||||
public abstract WeixinResponse doHandle0(WeixinRequest request,
|
||||
String message, M m) throws WeixinException;
|
||||
public abstract WeixinResponse doHandle0(WeixinRequest request, M message)
|
||||
throws WeixinException;
|
||||
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ public interface WeixinMessageHandler {
|
||||
* 微信消息
|
||||
* @return
|
||||
*/
|
||||
public boolean canHandle(WeixinRequest request, String message)
|
||||
public boolean canHandle(WeixinRequest request, Object message)
|
||||
throws WeixinException;
|
||||
|
||||
/**
|
||||
@ -36,6 +36,6 @@ public interface WeixinMessageHandler {
|
||||
* 微信消息
|
||||
* @return
|
||||
*/
|
||||
public WeixinResponse doHandle(WeixinRequest request, String message)
|
||||
public WeixinResponse doHandle(WeixinRequest request, Object message)
|
||||
throws WeixinException;
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.interceptor;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
import com.foxinmy.weixin4j.dispatcher.WeixinMessageAdapter;
|
||||
import com.foxinmy.weixin4j.exception.WeixinException;
|
||||
import com.foxinmy.weixin4j.handler.WeixinMessageHandler;
|
||||
import com.foxinmy.weixin4j.request.WeixinRequest;
|
||||
@ -17,45 +16,26 @@ import com.foxinmy.weixin4j.response.WeixinResponse;
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public abstract class MessageInterceptorAdapter<M> extends
|
||||
WeixinMessageAdapter<M> implements WeixinMessageInterceptor {
|
||||
|
||||
private M message;
|
||||
public abstract class MessageInterceptorAdapter implements
|
||||
WeixinMessageInterceptor {
|
||||
|
||||
@Override
|
||||
public boolean preHandle(ChannelHandlerContext context,
|
||||
WeixinRequest request, final String message,
|
||||
WeixinMessageHandler handler) throws WeixinException {
|
||||
this.message = super.messageRead(message);
|
||||
return preHandle0(context, request, this.message, handler);
|
||||
WeixinRequest request, Object message, WeixinMessageHandler handler)
|
||||
throws WeixinException {
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract boolean preHandle0(ChannelHandlerContext context,
|
||||
WeixinRequest request, M message, WeixinMessageHandler handler)
|
||||
throws WeixinException;
|
||||
|
||||
@Override
|
||||
public void postHandle(ChannelHandlerContext context,
|
||||
WeixinRequest request, WeixinResponse response, String message,
|
||||
WeixinRequest request, WeixinResponse response, Object message,
|
||||
WeixinMessageHandler handler) throws WeixinException {
|
||||
postHandle0(context, request, response, message, this.message, handler);
|
||||
}
|
||||
|
||||
public abstract void postHandle0(ChannelHandlerContext context,
|
||||
WeixinRequest request, WeixinResponse response, String message,
|
||||
M m, WeixinMessageHandler handler) throws WeixinException;
|
||||
|
||||
@Override
|
||||
public void afterCompletion(ChannelHandlerContext context,
|
||||
WeixinRequest request, String message,
|
||||
WeixinRequest request, Object message,
|
||||
WeixinMessageHandler handler, WeixinException exception)
|
||||
throws WeixinException {
|
||||
afterCompletion0(context, request, message, this.message, handler,
|
||||
exception);
|
||||
}
|
||||
|
||||
public abstract void afterCompletion0(ChannelHandlerContext context,
|
||||
WeixinRequest request, String message, M m,
|
||||
WeixinMessageHandler handler, WeixinException exception)
|
||||
throws WeixinException;
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ public interface WeixinMessageInterceptor {
|
||||
* @throws WeixinException
|
||||
*/
|
||||
boolean preHandle(ChannelHandlerContext context, WeixinRequest request,
|
||||
String message, WeixinMessageHandler handler)
|
||||
Object message, WeixinMessageHandler handler)
|
||||
throws WeixinException;
|
||||
|
||||
/**
|
||||
@ -52,7 +52,7 @@ public interface WeixinMessageInterceptor {
|
||||
* @throws WeixinException
|
||||
*/
|
||||
void postHandle(ChannelHandlerContext context, WeixinRequest request,
|
||||
WeixinResponse response, String message,
|
||||
WeixinResponse response, Object message,
|
||||
WeixinMessageHandler handler) throws WeixinException;
|
||||
|
||||
/**
|
||||
@ -71,6 +71,6 @@ public interface WeixinMessageInterceptor {
|
||||
* @throws WeixinException
|
||||
*/
|
||||
void afterCompletion(ChannelHandlerContext context, WeixinRequest request,
|
||||
String message, WeixinMessageHandler handler,
|
||||
Object message, WeixinMessageHandler handler,
|
||||
WeixinException exception) throws WeixinException;
|
||||
}
|
||||
|
||||
@ -8,28 +8,19 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.foxinmy.weixin4j.bean.AesToken;
|
||||
import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher;
|
||||
import com.foxinmy.weixin4j.exception.WeixinException;
|
||||
import com.foxinmy.weixin4j.request.WeixinMessage;
|
||||
import com.foxinmy.weixin4j.request.WeixinRequest;
|
||||
import com.foxinmy.weixin4j.type.EncryptType;
|
||||
import com.foxinmy.weixin4j.util.Consts;
|
||||
import com.foxinmy.weixin4j.util.HttpUtil;
|
||||
import com.foxinmy.weixin4j.util.MessageUtil;
|
||||
import com.foxinmy.weixin4j.util.StringUtil;
|
||||
import com.foxinmy.weixin4j.xml.CruxMessageHandler;
|
||||
|
||||
/**
|
||||
* 微信请求处理类
|
||||
@ -108,27 +99,17 @@ public class WeixinRequestHandler extends
|
||||
.addListener(ChannelFutureListener.CLOSE);
|
||||
return;
|
||||
}
|
||||
final String message = request.getOriginalContent();
|
||||
WeixinMessage weixinMessage;
|
||||
try {
|
||||
Unmarshaller unmarshaller = JAXBContext.newInstance(
|
||||
WeixinMessage.class).createUnmarshaller();
|
||||
Source source = new StreamSource(new ByteArrayInputStream(
|
||||
message.getBytes()));
|
||||
JAXBElement<WeixinMessage> jaxbElement = unmarshaller.unmarshal(
|
||||
source, WeixinMessage.class);
|
||||
weixinMessage = jaxbElement.getValue();
|
||||
} catch (JAXBException e) {
|
||||
throw new WeixinException(e);
|
||||
}
|
||||
CruxMessageHandler messageHandler = CruxMessageHandler.parser(request
|
||||
.getOriginalContent());
|
||||
ctx.channel().attr(Consts.ENCRYPTTYPE_KEY)
|
||||
.set(request.getEncryptType());
|
||||
ctx.channel().attr(Consts.USEROPENID_KEY)
|
||||
.set(weixinMessage.getFromUserName());
|
||||
.set(messageHandler.getFromUserName());
|
||||
if (StringUtil.isBlank(aesToken.getAppid())) {
|
||||
ctx.channel().attr(Consts.ACCOUNTOPENID_KEY)
|
||||
.set(weixinMessage.getToUserName());
|
||||
.set(messageHandler.getToUserName());
|
||||
}
|
||||
messageDispatcher.doDispatch(ctx, request, message);
|
||||
messageDispatcher.doDispatch(ctx, request,
|
||||
messageHandler.getUniqueKey());
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,57 +26,56 @@ public enum EventType {
|
||||
* @see com.foxinmy.weixin4j.message.event.LocationEventMessage
|
||||
*/
|
||||
location,
|
||||
/**
|
||||
* 菜单扫描事件
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.message.event.menu.MenuScanEventMessage
|
||||
*/
|
||||
scancode_push,
|
||||
/**
|
||||
* 菜单点击关键字事件
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.message.event.menu.MenuEventMessage
|
||||
* @see com.foxinmy.weixin4j.message.event.MenuEventMessage
|
||||
*/
|
||||
view,
|
||||
/**
|
||||
* 菜单点击链接事件
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.message.event.menu.MenuEventMessage
|
||||
* @see com.foxinmy.weixin4j.message.event.MenuEventMessage
|
||||
*/
|
||||
click,
|
||||
/**
|
||||
* 菜单扫描事件
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.message.event.MenuScanEventMessage
|
||||
*/
|
||||
scancode_push,
|
||||
/**
|
||||
* 菜单扫描并调出等待界面事件
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.message.event.menu.MenuScanEventMessage
|
||||
* @see com.foxinmy.weixin4j.message.event.MenuScanEventMessage
|
||||
*/
|
||||
scancode_waitmsg,
|
||||
/**
|
||||
* 菜单弹出拍照事件
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.message.event.menu.MenuPhotoEventMessage
|
||||
* @see com.foxinmy.weixin4j.message.event.MenuPhotoEventMessage
|
||||
*/
|
||||
pic_sysphoto,
|
||||
/**
|
||||
* 菜单弹出发图事件
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.message.event.menu.MenuPhotoEventMessage
|
||||
* @see com.foxinmy.weixin4j.message.event.MenuPhotoEventMessage
|
||||
*/
|
||||
pic_photo_or_album,
|
||||
/**
|
||||
* 菜单弹出发图事件
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.message.event.menu.MenuPhotoEventMessage
|
||||
* @see com.foxinmy.weixin4j.message.event.MenuPhotoEventMessage
|
||||
*/
|
||||
pic_weixin,
|
||||
/**
|
||||
* 菜单发送地理位置事件
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.message.event.menu.MenuLocationEventMessage
|
||||
* @see com.foxinmy.weixin4j.message.event.MenuLocationEventMessage
|
||||
*/
|
||||
location_select,
|
||||
|
||||
// ------------------------------公众平台特有------------------------------
|
||||
//
|
||||
|
||||
/**
|
||||
* 二维码扫描事件
|
||||
@ -114,6 +113,8 @@ public enum EventType {
|
||||
* @see com.foxinmy.weixin4j.mp.event.KfSwitchEventMessage
|
||||
*/
|
||||
kf_switch_session,
|
||||
|
||||
// ------------------------------企业号特有------------------------------
|
||||
/**
|
||||
* 异步任务完成事件
|
||||
*
|
||||
|
||||
@ -52,8 +52,7 @@ public final class ClassUtil {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
throw new UnsupportedOperationException(String.format(
|
||||
"unknow protocol:", protocol));
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,7 @@ import com.foxinmy.weixin4j.util.Consts;
|
||||
public class EncryptMessageHandler extends DefaultHandler {
|
||||
|
||||
private String encryptContent;
|
||||
private String content;
|
||||
|
||||
@Override
|
||||
public void startDocument() throws SAXException {
|
||||
@ -24,28 +25,30 @@ public class EncryptMessageHandler extends DefaultHandler {
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName,
|
||||
Attributes attributes) throws SAXException {
|
||||
if (qName.equalsIgnoreCase("encrypt")) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName)
|
||||
throws SAXException {
|
||||
if (localName.equalsIgnoreCase("encrypt")) {
|
||||
encryptContent = content;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length)
|
||||
throws SAXException {
|
||||
this.encryptContent = new String(ch, start, length);
|
||||
this.content = new String(ch, start, length);
|
||||
}
|
||||
|
||||
public String getEncryptContent() {
|
||||
return encryptContent;
|
||||
}
|
||||
|
||||
private final static EncryptMessageHandler messageHandler = new EncryptMessageHandler();
|
||||
|
||||
public static String parser(String xmlContent) throws RuntimeException {
|
||||
EncryptMessageHandler messageHandler = new EncryptMessageHandler();
|
||||
try {
|
||||
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
|
||||
xmlReader.setContentHandler(messageHandler);
|
||||
|
||||
@ -57,17 +57,11 @@ public class MessageServerStartup {
|
||||
* @throws WeixinException
|
||||
*/
|
||||
public void test3() throws WeixinException {
|
||||
// 文本消息回复
|
||||
// 针对文本消息回复
|
||||
WeixinMessageHandler messageHandler = new MessageHandlerAdapter<TextMessage>() {
|
||||
@Override
|
||||
public boolean canHandle0(WeixinRequest request, String message,
|
||||
TextMessage m) throws WeixinException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WeixinResponse doHandle0(WeixinRequest request,
|
||||
String message, TextMessage m) throws WeixinException {
|
||||
TextMessage message) throws WeixinException {
|
||||
return new TextResponse("HelloWorld!");
|
||||
}
|
||||
};
|
||||
@ -88,7 +82,7 @@ public class MessageServerStartup {
|
||||
WeixinMessageInterceptor interceptor = new WeixinMessageInterceptor() {
|
||||
@Override
|
||||
public boolean preHandle(ChannelHandlerContext context,
|
||||
WeixinRequest request, String message,
|
||||
WeixinRequest request, Object message,
|
||||
WeixinMessageHandler handler) throws WeixinException {
|
||||
context.writeAndFlush(new TextResponse("所有消息被拦截了!"));
|
||||
return false;
|
||||
@ -97,14 +91,14 @@ public class MessageServerStartup {
|
||||
@Override
|
||||
public void postHandle(ChannelHandlerContext context,
|
||||
WeixinRequest request, WeixinResponse response,
|
||||
String message, WeixinMessageHandler handler)
|
||||
Object message, WeixinMessageHandler handler)
|
||||
throws WeixinException {
|
||||
System.err.println("preHandle返回为true,执行handler后");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(ChannelHandlerContext context,
|
||||
WeixinRequest request, String message,
|
||||
WeixinRequest request, Object message,
|
||||
WeixinMessageHandler handler, WeixinException exception)
|
||||
throws WeixinException {
|
||||
System.err.println("请求处理完毕");
|
||||
@ -115,6 +109,6 @@ public class MessageServerStartup {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws WeixinException {
|
||||
new MessageServerStartup().test1();
|
||||
new MessageServerStartup().test5();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user