weixin4j-server:消息拦截器和处理器支持泛型

This commit is contained in:
jinyu 2015-05-15 12:51:19 +08:00
parent 33d5addc18
commit b6ec2485c9
18 changed files with 283 additions and 206 deletions

View File

@ -280,3 +280,7 @@
* 2015-05-13 * 2015-05-13
+ **weixin4j-server**: 新增了许多被动消息类型 + **weixin4j-server**: 新增了许多被动消息类型
* 2015-05-15
+ **weixin4j-server**: 消息拦截器和处理器支持泛型

View File

@ -29,3 +29,7 @@
* 2015-05-13 * 2015-05-13
+ 新增了许多被动消息类型 + 新增了许多被动消息类型
* 2015-05-15
+ **weixin4j-server**: 消息拦截器和处理器支持泛型

View File

@ -8,7 +8,6 @@ import org.slf4j.LoggerFactory;
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.interceptor.WeixinMessageInterceptor; import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor;
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;
@ -49,7 +48,7 @@ public class MessageHandlerExecutor {
return messageHandler; return messageHandler;
} }
public boolean applyPreHandle(WeixinRequest request, WeixinMessage message) public boolean applyPreHandle(WeixinRequest request, String 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++) {
@ -66,7 +65,7 @@ public class MessageHandlerExecutor {
} }
public void applyPostHandle(WeixinRequest request, WeixinResponse response, public void applyPostHandle(WeixinRequest request, WeixinResponse response,
WeixinMessage message) throws WeixinException { String message) throws WeixinException {
if (messageInterceptors == null) { if (messageInterceptors == null) {
return; return;
} }
@ -77,8 +76,8 @@ public class MessageHandlerExecutor {
} }
} }
public void triggerAfterCompletion(WeixinRequest request, public void triggerAfterCompletion(WeixinRequest request, String message,
WeixinMessage message, WeixinException ex) throws WeixinException { WeixinException exception) throws WeixinException {
if (messageInterceptors == null) { if (messageInterceptors == null) {
return; return;
} }
@ -86,7 +85,7 @@ public class MessageHandlerExecutor {
WeixinMessageInterceptor interceptor = messageInterceptors[i]; WeixinMessageInterceptor interceptor = messageInterceptors[i];
try { try {
interceptor.afterCompletion(context, request, message, interceptor.afterCompletion(context, request, message,
messageHandler, ex); messageHandler, exception);
} catch (WeixinException e) { } catch (WeixinException e) {
logger.error( logger.error(
"MessageInterceptor.afterCompletion threw exception", e); "MessageInterceptor.afterCompletion threw exception", e);

View File

@ -0,0 +1,69 @@
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

@ -16,7 +16,6 @@ import com.foxinmy.weixin4j.bean.BeanFactory;
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.interceptor.WeixinMessageInterceptor; import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor;
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 com.foxinmy.weixin4j.util.ClassUtil; import com.foxinmy.weixin4j.util.ClassUtil;
@ -65,7 +64,7 @@ public class WeixinMessageDispatcher {
} }
public void doDispatch(final ChannelHandlerContext context, public void doDispatch(final ChannelHandlerContext context,
final WeixinRequest request, final WeixinMessage message) final WeixinRequest request, final String message)
throws WeixinException { throws WeixinException {
MessageHandlerExecutor handlerExecutor = getHandlerExecutor(context, MessageHandlerExecutor handlerExecutor = getHandlerExecutor(context,
request, message); request, message);
@ -94,14 +93,14 @@ public class WeixinMessageDispatcher {
} }
protected void noHandlerFound(ChannelHandlerContext ctx, protected void noHandlerFound(ChannelHandlerContext ctx,
WeixinRequest request, WeixinMessage message) { WeixinRequest request, String 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, ChannelHandlerContext context, WeixinRequest request, String message)
WeixinMessage message) throws WeixinException { throws WeixinException {
WeixinMessageHandler messageHandler = null; WeixinMessageHandler messageHandler = null;
WeixinMessageHandler[] messageHandlers = getMessageHandlers(); WeixinMessageHandler[] messageHandlers = getMessageHandlers();
if (messageHandlers == null) { if (messageHandlers == null) {

View File

@ -1,12 +1,11 @@
package com.foxinmy.weixin4j.handler; package com.foxinmy.weixin4j.handler;
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.response.BlankResponse; import com.foxinmy.weixin4j.response.BlankResponse;
import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.response.WeixinResponse;
public class BlankMessageHandler extends MessageHandlerAdapter { public class BlankMessageHandler implements WeixinMessageHandler {
public final static BlankMessageHandler global = new BlankMessageHandler(); public final static BlankMessageHandler global = new BlankMessageHandler();
@ -15,7 +14,13 @@ public class BlankMessageHandler extends MessageHandlerAdapter {
} }
@Override @Override
public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message) public boolean canHandle(WeixinRequest request, String message)
throws WeixinException {
return true;
}
@Override
public WeixinResponse doHandle(WeixinRequest request, String message)
throws WeixinException { throws WeixinException {
return BlankResponse.global; return BlankResponse.global;
} }

View File

@ -1,23 +1,27 @@
package com.foxinmy.weixin4j.handler; package com.foxinmy.weixin4j.handler;
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.response.TextResponse; import com.foxinmy.weixin4j.response.TextResponse;
import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.response.WeixinResponse;
public class DebugMessageHandler extends MessageHandlerAdapter { public class DebugMessageHandler implements WeixinMessageHandler {
public static final DebugMessageHandler global = new DebugMessageHandler(); public static final DebugMessageHandler global = new DebugMessageHandler();
private DebugMessageHandler(){ private DebugMessageHandler() {
} }
@Override @Override
public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message) public boolean canHandle(WeixinRequest request, String message)
throws WeixinException { throws WeixinException {
return new TextResponse(String.format("%s,%s", request, return true;
message)); }
@Override
public WeixinResponse doHandle(WeixinRequest request, String message)
throws WeixinException {
return new TextResponse(message);
} }
} }

View File

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

View File

@ -1,7 +1,6 @@
package com.foxinmy.weixin4j.handler; package com.foxinmy.weixin4j.handler;
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.response.WeixinResponse; import com.foxinmy.weixin4j.response.WeixinResponse;
@ -25,7 +24,8 @@ public interface WeixinMessageHandler {
* 微信消息 * 微信消息
* @return * @return
*/ */
public boolean canHandle(WeixinRequest request, WeixinMessage message); public boolean canHandle(WeixinRequest request, String message)
throws WeixinException;
/** /**
* 处理请求 * 处理请求
@ -36,6 +36,6 @@ public interface WeixinMessageHandler {
* 微信消息 * 微信消息
* @return * @return
*/ */
public WeixinResponse doHandle(WeixinRequest request, WeixinMessage message) public WeixinResponse doHandle(WeixinRequest request, String message)
throws WeixinException; throws WeixinException;
} }

View File

@ -2,33 +2,60 @@ 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.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;
public abstract class MessageInterceptorAdapter implements /**
WeixinMessageInterceptor { * 消息拦截适配
*
* @className MessageInterceptorAdapter
* @author jy
* @date 2015年5月14日
* @since JDK 1.7
* @see
*/
public abstract class MessageInterceptorAdapter<M> extends
WeixinMessageAdapter<M> implements WeixinMessageInterceptor {
private M message;
@Override @Override
public boolean preHandle(ChannelHandlerContext context, public boolean preHandle(ChannelHandlerContext context,
WeixinRequest request, WeixinMessage message, WeixinRequest request, final String message,
WeixinMessageHandler handler) throws WeixinException { WeixinMessageHandler handler) throws WeixinException {
return true; this.message = super.messageRead(message);
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, WeixinRequest request, WeixinResponse response, String message,
WeixinMessage message, WeixinMessageHandler handler) WeixinMessageHandler handler) throws WeixinException {
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, WeixinMessage message, WeixinRequest request, String 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

@ -4,7 +4,6 @@ import io.netty.channel.ChannelHandlerContext;
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.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;
@ -22,7 +21,7 @@ public interface WeixinMessageInterceptor {
/** /**
* 执行handler前 * 执行handler前
* *
* @param ctx * @param context
* 通道环境 * 通道环境
* @param request * @param request
* 微信请求 * 微信请求
@ -33,14 +32,14 @@ public interface WeixinMessageInterceptor {
* @return 返回true执行下一个拦截器 * @return 返回true执行下一个拦截器
* @throws WeixinException * @throws WeixinException
*/ */
boolean preHandle(ChannelHandlerContext ctx, WeixinRequest request, boolean preHandle(ChannelHandlerContext context, WeixinRequest request,
WeixinMessage message, WeixinMessageHandler handler) String message, WeixinMessageHandler handler)
throws WeixinException; throws WeixinException;
/** /**
* 执行handler后 * 执行handler后
* *
* @param ctx * @param context
* 通道环境 * 通道环境
* @param request * @param request
* 微信请求 * 微信请求
@ -52,14 +51,14 @@ public interface WeixinMessageInterceptor {
* 消息处理器 * 消息处理器
* @throws WeixinException * @throws WeixinException
*/ */
void postHandle(ChannelHandlerContext ctx, WeixinRequest request, void postHandle(ChannelHandlerContext context, WeixinRequest request,
WeixinResponse response, WeixinMessage message, WeixinResponse response, String message,
WeixinMessageHandler handler) throws WeixinException; WeixinMessageHandler handler) throws WeixinException;
/** /**
* 全部执行后 * 全部执行后
* *
* @param ctx * @param context
* 通道环境 * 通道环境
* @param request * @param request
* 微信请求 * 微信请求
@ -71,7 +70,7 @@ public interface WeixinMessageInterceptor {
* 执行异常 * 执行异常
* @throws WeixinException * @throws WeixinException
*/ */
void afterCompletion(ChannelHandlerContext ctx, WeixinRequest request, void afterCompletion(ChannelHandlerContext context, WeixinRequest request,
WeixinMessage message, WeixinMessageHandler handler, String message, WeixinMessageHandler handler,
WeixinException exception) throws WeixinException; WeixinException exception) throws WeixinException;
} }

View File

@ -4,7 +4,7 @@ import java.io.Serializable;
import java.util.List; import java.util.List;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlElementWrapper;
/** /**
* 弹出拍照或者相册发图的事件推送(pic_sysphoto|pic_photo_or_album|pic_weixin) * 弹出拍照或者相册发图的事件推送(pic_sysphoto|pic_photo_or_album|pic_weixin)
@ -53,7 +53,8 @@ public class MenuPhotoEventMessage extends MenuEventMessage {
/** /**
* 图片列表 * 图片列表
*/ */
@XmlElement(name = "PicList") @XmlElementWrapper(name = "PicList")
@XmlElement(name = "item")
private List<PictureItem> items; private List<PictureItem> items;
public int getCount() { public int getCount() {
@ -79,7 +80,6 @@ public class MenuPhotoEventMessage extends MenuEventMessage {
* @since JDK 1.7 * @since JDK 1.7
* @see * @see
*/ */
@XmlRootElement(name = "item")
public static class PictureItem implements Serializable { public static class PictureItem implements Serializable {
private static final long serialVersionUID = -7636697449096645590L; private static final long serialVersionUID = -7636697449096645590L;
@ -90,6 +90,10 @@ public class MenuPhotoEventMessage extends MenuEventMessage {
@XmlElement(name = "PicMd5Sum") @XmlElement(name = "PicMd5Sum")
private String md5; private String md5;
public String getMd5() {
return md5;
}
@Override @Override
public String toString() { public String toString() {
return "PictureItem [md5=" + md5 + "]"; return "PictureItem [md5=" + md5 + "]";

View File

@ -3,7 +3,6 @@ package com.foxinmy.weixin4j.request;
import java.io.Serializable; import java.io.Serializable;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/** /**
* 基本被动消息 * 基本被动消息
@ -14,7 +13,6 @@ import javax.xml.bind.annotation.XmlRootElement;
* @since JDK 1.7 * @since JDK 1.7
* @see * @see
*/ */
@XmlRootElement(name = "xml")
public class WeixinMessage implements Serializable { public class WeixinMessage implements Serializable {
private static final long serialVersionUID = 7761192742840031607L; private static final long serialVersionUID = 7761192742840031607L;
@ -22,27 +20,33 @@ public class WeixinMessage implements Serializable {
/** /**
* 开发者微信号 * 开发者微信号
*/ */
@XmlElement(name = "ToUserName")
private String toUserName; private String toUserName;
/** /**
* 发送方账号 即用户的openid * 发送方账号 即用户的openid
*/ */
@XmlElement(name = "FromUserName")
private String fromUserName; private String fromUserName;
/** /**
* 消息创建时间 系统毫秒数 * 消息创建时间 系统毫秒数
*/ */
@XmlElement(name = "CreateTime")
private long createTime; private long createTime;
/** /**
* 消息类型 * 消息类型
* *
*/ */
@XmlElement(name = "MsgType")
private String msgType; private String msgType;
/** /**
* 消息ID 可用于排重 * 消息ID 可用于排重
*/ */
@XmlElement(name = "MsgId")
private long msgId; private long msgId;
/** /**
* 企业号独有的应用ID * 企业号独有的应用ID
*/ */
@XmlElement(name = "AgentID")
private String agentId; private String agentId;
public WeixinMessage() { public WeixinMessage() {
@ -57,56 +61,26 @@ public class WeixinMessage implements Serializable {
return toUserName; return toUserName;
} }
@XmlElement(name = "ToUserName")
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
}
public String getFromUserName() { public String getFromUserName() {
return fromUserName; return fromUserName;
} }
@XmlElement(name = "FromUserName")
public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
}
public long getCreateTime() { public long getCreateTime() {
return createTime; return createTime;
} }
@XmlElement(name = "CreateTime")
public void setCreateTime(long createTime) {
this.createTime = createTime;
}
public String getMsgType() { public String getMsgType() {
return msgType; return msgType;
} }
@XmlElement(name = "MsgType")
public void setMsgType(String msgType) {
this.msgType = msgType;
}
public long getMsgId() { public long getMsgId() {
return msgId; return msgId;
} }
@XmlElement(name = "MsgId")
public void setMsgId(long msgId) {
this.msgId = msgId;
}
public String getAgentId() { public String getAgentId() {
return agentId; return agentId;
} }
@XmlElement(name = "AgentID")
public void setAgentId(String agentId) {
this.agentId = agentId;
}
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;

View File

@ -17,17 +17,10 @@ public class WeixinRequest implements Serializable, Cloneable {
private static final long serialVersionUID = -9157395300510879866L; private static final long serialVersionUID = -9157395300510879866L;
// 以下字段是加密方式为安全模式时的参数
/** /**
* 加密后的内容 * 请求的方式
*/ */
private String encryptContent; private String method;
/**
* 加密类型
*
* @see com.foxinmy.weixin4j.type.EncryptType
*/
private EncryptType encryptType;
// 以下字段每次被动消息时都会带上 // 以下字段每次被动消息时都会带上
/** /**
@ -50,85 +43,72 @@ public class WeixinRequest implements Serializable, Cloneable {
* AES模式下消息签名 * AES模式下消息签名
*/ */
private String msgSignature; private String msgSignature;
/**
* 加密类型(POST时存在)
*
* @see com.foxinmy.weixin4j.type.EncryptType
*/
private EncryptType encryptType;
/** /**
* xml消息明文主体 * xml消息明文主体
*/ */
private String originalContent; private String originalContent;
/** /**
* 请求的方式 * xml消息密文主体(AES时存在)
*/ */
private String method; private String encryptContent;
public String getEncryptContent() { public WeixinRequest(String method, EncryptType encryptType,
return encryptContent; String echoStr, String timeStamp, String nonce, String signature,
} String msgSignature, String originalContent, String encryptContent) {
this.method = method;
public void setEncryptContent(String encryptContent) {
this.encryptContent = encryptContent;
}
public EncryptType getEncryptType() {
return encryptType;
}
public void setEncryptType(EncryptType encryptType) {
this.encryptType = encryptType; this.encryptType = encryptType;
}
public String getEchoStr() {
return echoStr;
}
public void setEchoStr(String echoStr) {
this.echoStr = echoStr; this.echoStr = echoStr;
}
public String getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(String timeStamp) {
this.timeStamp = timeStamp; this.timeStamp = timeStamp;
}
public String getNonce() {
return nonce;
}
public void setNonce(String nonce) {
this.nonce = nonce; this.nonce = nonce;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature; this.signature = signature;
}
public String getMsgSignature() {
return msgSignature;
}
public void setMsgSignature(String msgSignature) {
this.msgSignature = msgSignature; this.msgSignature = msgSignature;
}
public String getOriginalContent() {
return originalContent;
}
public void setOriginalContent(String originalContent) {
this.originalContent = originalContent; this.originalContent = originalContent;
this.encryptContent = encryptContent;
} }
public String getMethod() { public String getMethod() {
return method; return method;
} }
public void setMethod(String method) { public String getEchoStr() {
this.method = method; return echoStr;
}
public String getTimeStamp() {
return timeStamp;
}
public String getNonce() {
return nonce;
}
public String getSignature() {
return signature;
}
public String getMsgSignature() {
return msgSignature;
}
public EncryptType getEncryptType() {
return encryptType;
}
public String getOriginalContent() {
return originalContent;
}
public String getEncryptContent() {
return encryptContent;
} }
@Override @Override

View File

@ -44,8 +44,6 @@ public class WeixinMessageDecoder extends
protected void decode(ChannelHandlerContext ctx, FullHttpRequest req, protected void decode(ChannelHandlerContext ctx, FullHttpRequest req,
List<Object> out) throws WeixinException { List<Object> out) throws WeixinException {
String content = req.content().toString(Consts.UTF_8); String content = req.content().toString(Consts.UTF_8);
WeixinRequest message = new WeixinRequest();
message.setMethod(req.getMethod().name());
QueryStringDecoder queryDecoder = new QueryStringDecoder(req.getUri(), QueryStringDecoder queryDecoder = new QueryStringDecoder(req.getUri(),
true); true);
log.info("\n=================receive request================="); log.info("\n=================receive request=================");
@ -53,40 +51,35 @@ public class WeixinMessageDecoder extends
log.info("{}", req.getUri()); log.info("{}", req.getUri());
log.info("{}", content); log.info("{}", content);
Map<String, List<String>> parameters = queryDecoder.parameters(); Map<String, List<String>> parameters = queryDecoder.parameters();
String encryptType = parameters.containsKey("encrypt_type") ? parameters EncryptType encryptType = parameters.containsKey("encrypt_type") ? EncryptType
.get("encrypt_type").get(0) : EncryptType.RAW.name(); .valueOf(parameters.get("encrypt_type").get(0).toUpperCase())
message.setEncryptType(EncryptType.valueOf(encryptType.toUpperCase())); : EncryptType.RAW;
String echoStr = parameters.containsKey("echostr") ? parameters.get( String echoStr = parameters.containsKey("echostr") ? parameters.get(
"echostr").get(0) : ""; "echostr").get(0) : "";
message.setEchoStr(echoStr);
String timeStamp = parameters.containsKey("timestamp") ? parameters String timeStamp = parameters.containsKey("timestamp") ? parameters
.get("timestamp").get(0) : ""; .get("timestamp").get(0) : "";
message.setTimeStamp(timeStamp);
String nonce = parameters.containsKey("nonce") ? parameters String nonce = parameters.containsKey("nonce") ? parameters
.get("nonce").get(0) : ""; .get("nonce").get(0) : "";
message.setNonce(nonce);
String signature = parameters.containsKey("signature") ? parameters String signature = parameters.containsKey("signature") ? parameters
.get("signature").get(0) : ""; .get("signature").get(0) : "";
message.setSignature(signature);
String msgSignature = parameters.containsKey("msg_signature") ? parameters String msgSignature = parameters.containsKey("msg_signature") ? parameters
.get("msg_signature").get(0) : ""; .get("msg_signature").get(0) : "";
message.setMsgSignature(msgSignature); String originalContent = content;
String encryptContent = null;
if (!content.isEmpty()) { if (!content.isEmpty()) {
if (message.getEncryptType() == EncryptType.AES) { if (encryptType == EncryptType.AES) {
if (StringUtil.isBlank(aesToken.getAesKey()) if (StringUtil.isBlank(aesToken.getAesKey())
|| StringUtil.isBlank(aesToken.getAppid())) { || StringUtil.isBlank(aesToken.getAppid())) {
throw new WeixinException( throw new WeixinException(
"AESEncodingKey or AppId not be null in AES mode"); "AESEncodingKey or AppId not be null in AES mode");
} }
String encryptContent = EncryptMessageHandler.parser(content); encryptContent = EncryptMessageHandler.parser(content);
message.setEncryptContent(encryptContent); originalContent = MessageUtil.aesDecrypt(aesToken.getAppid(),
message.setOriginalContent(MessageUtil.aesDecrypt( aesToken.getAesKey(), encryptContent);
aesToken.getAppid(), aesToken.getAesKey(), }
}
out.add(new WeixinRequest(req.getMethod().name(), encryptType, echoStr,
timeStamp, nonce, signature, msgSignature, originalContent,
encryptContent)); encryptContent));
} else {
message.setOriginalContent(content);
}
}
out.add(message);
} }
} }

View File

@ -11,8 +11,11 @@ import io.netty.handler.codec.http.HttpMethod;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException; import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller; 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;
@ -23,7 +26,6 @@ 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.type.EncryptType; import com.foxinmy.weixin4j.type.EncryptType;
import com.foxinmy.weixin4j.util.ClassUtil;
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;
@ -44,17 +46,11 @@ public class WeixinRequestHandler extends
private final AesToken aesToken; private final AesToken aesToken;
private final WeixinMessageDispatcher messageDispatcher; private final WeixinMessageDispatcher messageDispatcher;
private final JAXBContext jaxbContext;
public WeixinRequestHandler(AesToken aesToken, public WeixinRequestHandler(AesToken aesToken,
WeixinMessageDispatcher messageDispatcher) throws WeixinException { WeixinMessageDispatcher messageDispatcher) throws WeixinException {
this.aesToken = aesToken; this.aesToken = aesToken;
this.messageDispatcher = messageDispatcher; this.messageDispatcher = messageDispatcher;
try {
jaxbContext = JAXBContext.newInstance(WeixinMessage.class);
} catch (JAXBException e) {
throw new WeixinException(e);
}
} }
public void channelReadComplete(ChannelHandlerContext ctx) { public void channelReadComplete(ChannelHandlerContext ctx) {
@ -112,12 +108,16 @@ public class WeixinRequestHandler extends
.addListener(ChannelFutureListener.CLOSE); .addListener(ChannelFutureListener.CLOSE);
return; return;
} }
WeixinMessage weixinMessage = null; final String message = request.getOriginalContent();
WeixinMessage weixinMessage;
try { try {
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); Unmarshaller unmarshaller = JAXBContext.newInstance(
weixinMessage = (WeixinMessage) jaxbUnmarshaller WeixinMessage.class).createUnmarshaller();
.unmarshal(new ByteArrayInputStream(request Source source = new StreamSource(new ByteArrayInputStream(
.getOriginalContent().getBytes(Consts.UTF_8))); message.getBytes()));
JAXBElement<WeixinMessage> jaxbElement = unmarshaller.unmarshal(
source, WeixinMessage.class);
weixinMessage = jaxbElement.getValue();
} catch (JAXBException e) { } catch (JAXBException e) {
throw new WeixinException(e); throw new WeixinException(e);
} }
@ -129,10 +129,6 @@ public class WeixinRequestHandler extends
ctx.channel().attr(Consts.ACCOUNTOPENID_KEY) ctx.channel().attr(Consts.ACCOUNTOPENID_KEY)
.set(weixinMessage.getToUserName()); .set(weixinMessage.getToUserName());
} }
final WeixinRequest cloneRequest = (WeixinRequest) ClassUtil messageDispatcher.doDispatch(ctx, request, message);
.deepClone(request);
final WeixinMessage cloneMessage = (WeixinMessage) ClassUtil
.deepClone(weixinMessage);
messageDispatcher.doDispatch(ctx, cloneRequest, cloneMessage);
} }
} }

View File

@ -77,7 +77,7 @@ public class WeixinResponseEncoder extends
aesToken.getAesKey(), content.toString()); aesToken.getAesKey(), content.toString());
String msgSignature = MessageUtil.signature( String msgSignature = MessageUtil.signature(
aesToken.getToken(), nonce, timestamp, encrtypt); aesToken.getToken(), nonce, timestamp, encrtypt);
content.delete(0, content.length() - 1); content.delete(0, content.length());
content.append("<xml>"); content.append("<xml>");
content.append(String.format("<Nonce><![CDATA[%s]]></Nonce>", content.append(String.format("<Nonce><![CDATA[%s]]></Nonce>",
nonce)); nonce));

View File

@ -5,10 +5,10 @@ import io.netty.channel.ChannelHandlerContext;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.handler.BlankMessageHandler; import com.foxinmy.weixin4j.handler.BlankMessageHandler;
import com.foxinmy.weixin4j.handler.DebugMessageHandler; import com.foxinmy.weixin4j.handler.DebugMessageHandler;
import com.foxinmy.weixin4j.handler.MessageHandlerAdapter;
import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.handler.WeixinMessageHandler;
import com.foxinmy.weixin4j.interceptor.MessageInterceptorAdapter;
import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor; import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor;
import com.foxinmy.weixin4j.request.WeixinMessage; 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;
import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.response.WeixinResponse;
@ -57,18 +57,18 @@ public class MessageServerStartup {
* @throws WeixinException * @throws WeixinException
*/ */
public void test3() throws WeixinException { public void test3() throws WeixinException {
// 回复文本消息 // 文本消息回复
WeixinMessageHandler messageHandler = new WeixinMessageHandler() { WeixinMessageHandler messageHandler = new MessageHandlerAdapter<TextMessage>() {
@Override @Override
public WeixinResponse doHandle(WeixinRequest request, public boolean canHandle0(WeixinRequest request, String message,
WeixinMessage message) throws WeixinException { TextMessage m) throws WeixinException {
return new TextResponse("HelloWorld!"); return true;
} }
@Override @Override
public boolean canHandle(WeixinRequest request, public WeixinResponse doHandle0(WeixinRequest request,
WeixinMessage message) { String message, TextMessage m) throws WeixinException {
return message.getMsgType().equals("text"); return new TextResponse("HelloWorld!");
} }
}; };
// 当消息类型为文本(text)时回复HelloWorld, 否则回复调试消息 // 当消息类型为文本(text)时回复HelloWorld, 否则回复调试消息
@ -85,26 +85,26 @@ public class MessageServerStartup {
public void test5() throws WeixinException { public void test5() throws WeixinException {
// 拦截所有请求 // 拦截所有请求
WeixinMessageInterceptor interceptor = new MessageInterceptorAdapter() { WeixinMessageInterceptor interceptor = new WeixinMessageInterceptor() {
@Override @Override
public boolean preHandle(ChannelHandlerContext context, public boolean preHandle(ChannelHandlerContext context,
WeixinRequest request, WeixinMessage message, WeixinRequest request, String message,
WeixinMessageHandler handler) throws WeixinException { WeixinMessageHandler handler) throws WeixinException {
context.write(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) String 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, String message,
WeixinMessageHandler handler, WeixinException exception) WeixinMessageHandler handler, WeixinException exception)
throws WeixinException { throws WeixinException {
System.err.println("请求处理完毕"); System.err.println("请求处理完毕");
@ -115,6 +115,6 @@ public class MessageServerStartup {
} }
public static void main(String[] args) throws WeixinException { public static void main(String[] args) throws WeixinException {
new MessageServerStartup().test5(); new MessageServerStartup().test1();
} }
} }