在企业号工程上新增netty服务&消息分发

This commit is contained in:
jy.hu
2014-11-24 14:32:08 +08:00
parent 2ece136d46
commit 2cf2227822
104 changed files with 1253 additions and 326 deletions
+1 -1
View File
@@ -47,7 +47,7 @@ weixin.properties说明
示例(properties中换行用右斜杆\\)
> account={"id":"appId","secret":"appSecret",
> "token":"开放者的token 必须","openId":"公众号的openid 非必须",
> "token":"开放者的token","openId":"公众号的openid 非必须",
> "encodingAesKey":"公众号设置了加密方式且为「安全模式」需要填入",
> "mchId":"V3.x版本下的微信商户号",
> "partnerId":"财付通的商户号","partnerKey":"财付通商户权限密钥Key",
-5
View File
@@ -24,11 +24,6 @@
</plugins>
</build>
<dependencies>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>${jaxen.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
@@ -42,10 +42,10 @@ import com.foxinmy.weixin4j.http.SSLHttpRequest;
import com.foxinmy.weixin4j.http.XmlResult;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.converter.RefundConverter;
import com.foxinmy.weixin4j.mp.payment.ApiResult;
import com.foxinmy.weixin4j.mp.payment.PayUtil;
import com.foxinmy.weixin4j.mp.payment.Refund;
import com.foxinmy.weixin4j.mp.payment.RefundConverter;
import com.foxinmy.weixin4j.mp.payment.RefundResult;
import com.foxinmy.weixin4j.mp.payment.v2.Order;
import com.foxinmy.weixin4j.mp.type.BillType;
@@ -1,30 +0,0 @@
package com.foxinmy.weixin4j.mp.converter;
import com.foxinmy.weixin4j.msg.model.Text;
import com.thoughtworks.xstream.converters.SingleValueConverter;
/**
* Text回复消息转换
*
* @className TextConverter
* @author jy
* @date 2014年11月22日
* @since JDK 1.7
*/
public class TextConverter implements SingleValueConverter {
@Override
public boolean canConvert(@SuppressWarnings("rawtypes") Class clazz) {
return clazz.equals(Text.class);
}
@Override
public String toString(Object obj) {
return ((Text) obj).getContent();
}
@Override
public Object fromString(String text) {
return new Text(text);
}
}
@@ -1,113 +0,0 @@
package com.foxinmy.weixin4j.mp.message;
import org.apache.commons.lang3.StringUtils;
import com.foxinmy.weixin4j.model.BaseMsg;
import com.foxinmy.weixin4j.mp.converter.TextConverter;
import com.foxinmy.weixin4j.msg.model.Article;
import com.foxinmy.weixin4j.msg.model.Base;
import com.foxinmy.weixin4j.msg.model.News;
import com.foxinmy.weixin4j.msg.model.Responseable;
import com.foxinmy.weixin4j.util.ClassUtil;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 被动消息
* <p>
* <font color="red">回复图片等多媒体消息时需要预先上传多媒体文件到微信服务器,
* 假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试</font>
* </p>
*
* @className ResponseMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.model.Text
* @see com.foxinmy.weixin4j.msg.model.Image
* @see com.foxinmy.weixin4j.msg.model.Voice
* @see com.foxinmy.weixin4j.msg.model.Video
* @see com.foxinmy.weixin4j.msg.model.Music
* @see com.foxinmy.weixin4j.msg.model.News
* @see com.foxinmy.weixin4j.msg.model.Trans
* @see <a href=
* "http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF"
* >回复被动消息</a>
*/
@XStreamAlias("xml")
public class ResponseMessage extends BaseMsg {
private static final long serialVersionUID = 7761192742840031607L;
protected final static XStream xmlStream = XStream.get();
static {
Class<?>[] classes = ClassUtil.getClasses(Base.class.getPackage())
.toArray(new Class[0]);
xmlStream.autodetectAnnotations(true);
xmlStream.processAnnotations(classes);
xmlStream.processAnnotations(ResponseMessage.class);
xmlStream.registerConverter(new TextConverter());
xmlStream.omitField(BaseMsg.class, "msgId");
xmlStream.alias("item", Article.class);
xmlStream.addImplicitCollection(News.class, "articles");
xmlStream.aliasSystemAttribute(null, "class");
}
private String attach; // 附加数据
private final Base box;
public ResponseMessage(Base box) {
this(box, null);
}
public ResponseMessage(Base box, BaseMsg inMessage) {
this(box, inMessage.getFromUserName(), inMessage.getToUserName());
}
public ResponseMessage(Base box, String toUserName, String fromUserName) {
super(box.getMediaType().name(), toUserName, fromUserName);
this.box = box;
}
public String getAttach() {
return attach;
}
public Base getBox() {
return box;
}
/**
* 消息对象转换为微信服务器接受的xml格式消息 </br> <font
* color="color">需Responseable标识,否则返回空</font>
*
* @see com.foxinmy.weixin4j.msg.model.Responseable
* @return xml字符串
*/
public String toXml() {
// check responseable
if (!(box instanceof Responseable)) {
return "";
}
String boxAlias = StringUtils.capitalize(getMsgType());
XStreamAlias alias = box.getClass().getAnnotation(XStreamAlias.class);
if (alias != null) {
boxAlias = alias.value();
}
xmlStream.aliasField(boxAlias, ResponseMessage.class, "box");
if (box instanceof News) {
attach = Integer.toString(((News) box).getArticles().size());
xmlStream.aliasField("ArticleCount", ResponseMessage.class,
"attach");
}
return xmlStream.toXML(this);
}
@Override
public String toString() {
return "ResponseMessage [box=" + box + ", getToUserName()="
+ getToUserName() + ", getFromUserName()=" + getFromUserName()
+ ", getCreateTime()=" + getCreateTime() + ", getMsgType()="
+ getMsgType() + "]";
}
}
@@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.converter;
package com.foxinmy.weixin4j.mp.payment;
import java.lang.reflect.Field;
import java.util.HashMap;
@@ -9,8 +9,6 @@ import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.foxinmy.weixin4j.mp.payment.Refund;
import com.foxinmy.weixin4j.mp.payment.RefundDetail;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
@@ -1,5 +0,0 @@
package com.foxinmy.weixin4j.mp.type;
public enum EncryptType {
RAW, AES
}
@@ -5,7 +5,6 @@ import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.model.BaseMsg;
import com.foxinmy.weixin4j.mp.message.ResponseMessage;
import com.foxinmy.weixin4j.msg.TextMessage;
import com.foxinmy.weixin4j.msg.model.Image;
import com.foxinmy.weixin4j.msg.model.Music;
@@ -14,6 +13,7 @@ import com.foxinmy.weixin4j.msg.model.Text;
import com.foxinmy.weixin4j.msg.model.Trans;
import com.foxinmy.weixin4j.msg.model.Video;
import com.foxinmy.weixin4j.msg.model.Voice;
import com.foxinmy.weixin4j.response.ResponseMessage;
/**
* 发送消息格式测试
+1 -1
View File
@@ -27,7 +27,7 @@ weixin4j-mp-server
示例(properties中换行用右斜杆\\)
> account={"id":"appId","secret":"appSecret",
> "token":"开放者的token 必须","openId":"公众号的openid 非必须",
> "token":"开放者的token","openId":"公众号的openid 非必须",
> "encodingAesKey":"公众号设置了加密方式且为「安全模式」时需要填入",
> "mchId":"V3.x版本下的微信商户号",
> "partnerId":"财付通的商户号","partnerKey":"财付通商户权限密钥Key",
@@ -1,51 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.dom4j.DocumentException;
import com.foxinmy.weixin4j.model.BaseMsg;
import com.foxinmy.weixin4j.mp.message.ResponseMessage;
import com.foxinmy.weixin4j.util.MessageUtil;
import com.foxinmy.weixin4j.xml.XStream;
/**
* 继承的类需实现execute(M inMessage)
*
* @className AbstractAction
* @author jy
* @date 2014年10月12日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.mp.action.WeixinAction
*/
@SuppressWarnings("unchecked")
public abstract class AbstractAction<M extends BaseMsg> implements
WeixinAction {
public abstract ResponseMessage execute(M inMessage);
@Override
public ResponseMessage execute(String msg) throws DocumentException {
BaseMsg message = MessageUtil.xml2msg(msg);
if (message == null) {
Class<M> messageClass = getGenericType();
XStream xstream = XStream.get();
xstream.processAnnotations(messageClass);
xstream.alias("xml", messageClass);
return execute(xstream.fromXML(msg, messageClass));
}
return execute((M) message);
}
private Class<M> getGenericType() {
Class<M> clazz = null;
Type type = getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
ParameterizedType ptype = ((ParameterizedType) type);
Type[] args = ptype.getActualTypeArguments();
clazz = (Class<M>) args[0];
}
return clazz;
}
}
@@ -1,21 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.model.BaseMsg;
import com.foxinmy.weixin4j.mp.message.ResponseMessage;
/**
* 回复一个空字符串 而不是一个XML结构体中content字段的内容为空
*
* @className BlankAction
* @author jy.hu
* @date 2014年10月2日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.mp.action.AbstractAction
*/
public class BlankAction<M extends BaseMsg> extends AbstractAction<M> {
@Override
public ResponseMessage execute(M inMessage) {
return null;
}
}
@@ -1,22 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.model.BaseMsg;
import com.foxinmy.weixin4j.mp.message.ResponseMessage;
import com.foxinmy.weixin4j.msg.model.Text;
/**
* 调试输出用户消息
*
* @className DebugAction
* @author jy
* @date 2014年10月8日
* @since JDK 1.7
* @see
*/
public abstract class DebugAction<M extends BaseMsg> extends AbstractAction<M> {
@Override
public ResponseMessage execute(M message) {
return new ResponseMessage(new Text(message.toString()), message);
}
}
@@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.ImageMessage;
import com.foxinmy.weixin4j.type.MessageType;
@@ -13,7 +14,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.ImageMessage
*/
@Action(msgType = MessageType.image)
@ActionAnnotation(msgType = MessageType.image)
public class ImageAction extends DebugAction<ImageMessage> {
}
@@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.LinkMessage;
import com.foxinmy.weixin4j.type.MessageType;
@@ -13,7 +14,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.LinkMessage
*/
@Action(msgType = MessageType.link)
@ActionAnnotation(msgType = MessageType.link)
public class LinkAction extends DebugAction<LinkMessage> {
}
@@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.LocationMessage;
import com.foxinmy.weixin4j.type.MessageType;
@@ -13,7 +14,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.LocationMessage
*/
@Action(msgType = MessageType.location)
@ActionAnnotation(msgType = MessageType.location)
public class LocationAction extends DebugAction<LocationMessage> {
}
@@ -1,9 +1,10 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.mp.message.ResponseMessage;
import com.foxinmy.weixin4j.action.AbstractAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.TextMessage;
import com.foxinmy.weixin4j.msg.model.Text;
import com.foxinmy.weixin4j.response.ResponseMessage;
import com.foxinmy.weixin4j.type.MessageType;
/**
@@ -15,7 +16,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.TextMessage
*/
@Action(msgType = MessageType.text)
@ActionAnnotation(msgType = MessageType.text)
public class TextAction extends AbstractAction<TextMessage> {
@Override
@@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.VideoMessage;
import com.foxinmy.weixin4j.type.MessageType;
@@ -13,7 +14,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.VideoMessage
*/
@Action(msgType = MessageType.video)
@ActionAnnotation(msgType = MessageType.video)
public class VideoAction extends DebugAction<VideoMessage> {
}
@@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.VoiceMessage;
import com.foxinmy.weixin4j.type.MessageType;
@@ -13,7 +14,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.VoiceMessage
*/
@Action(msgType = MessageType.voice)
@ActionAnnotation(msgType = MessageType.voice)
public class VoiceAction extends DebugAction<VoiceMessage> {
}
@@ -1,20 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import org.dom4j.DocumentException;
import com.foxinmy.weixin4j.mp.message.ResponseMessage;
/**
* 消息处理接口
*
* @className Action
* @author jy.hu
* @date 2014年10月2日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.mp.action.AbstractAction
* @see com.foxinmy.weixin4j.mp.action.BlankAction
* @see com.foxinmy.weixin4j.mp.action.DebugAction
*/
public interface WeixinAction {
public ResponseMessage execute(String inMsg) throws DocumentException;
}
@@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.LocationEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
@@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.LocationEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.location })
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.location })
public class LocationAction extends DebugAction<LocationEventMessage> {
}
@@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.MassEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
@@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.MassEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.massendjobfinish })
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.massendjobfinish })
public class MassSendAction extends DebugAction<MassEventMessage> {
}
@@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
@@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.click })
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.click })
public class MenuClickAction extends DebugAction<MenuEventMessage> {
}
@@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.menu.MenuLocationEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
@@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuLocationEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.location_select })
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.location_select })
public class MenuLocationAction extends DebugAction<MenuLocationEventMessage> {
}
@@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
@@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage
*/
@Action(msgType = MessageType.event, eventType = {
@ActionAnnotation(msgType = MessageType.event, eventType = {
EventType.pic_photo_or_album, EventType.pic_sysphoto,
EventType.pic_weixin })
public class MenuPhotoAction extends DebugAction<MenuPhotoEventMessage> {
@@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
@@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.scancode_push,
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.scancode_push,
EventType.scancode_waitmsg })
public class MenuScanAction extends DebugAction<MenuScanEventMessage> {
@@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
@@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.view })
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.view })
public class MenuViewAction extends DebugAction<MenuEventMessage> {
}
@@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.ScanEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
@@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.ScanEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.scan })
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.scan })
public class ScanAction extends DebugAction<ScanEventMessage> {
}
@@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.ScribeEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
@@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.ScribeEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.subscribe })
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.subscribe })
public class SubscribeAction extends DebugAction<ScribeEventMessage> {
}
@@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
@@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.templatesendjobfinish })
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.templatesendjobfinish })
public class TemplateSendAction extends
DebugAction<TemplatesendjobfinishMessage> {
@@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.ScribeEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
@@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.ScribeEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.unsubscribe })
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.unsubscribe })
public class UnsubscribeAction extends DebugAction<ScribeEventMessage> {
}
@@ -1,29 +0,0 @@
package com.foxinmy.weixin4j.mp.mapping;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 获取默认的Mapping Key 如text,event_click
*
* @className AbstractActionMapping
* @author jy
* @date 2014年10月28日
* @since JDK 1.7
* @see
*/
public abstract class AbstractActionMapping implements ActionMapping {
protected String getMappingKey(String xmlMsg) throws DocumentException {
Document doc = DocumentHelper.parseText(xmlMsg);
String msgType = doc.selectSingleNode("/xml/MsgType").getStringValue();
if (msgType.equalsIgnoreCase(MessageType.event.name())) {
msgType += "_"
+ doc.selectSingleNode("/xml/Event").getStringValue();
}
return msgType.toLowerCase();
}
}
@@ -1,26 +0,0 @@
package com.foxinmy.weixin4j.mp.mapping;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 标注Action类来处理消息请求
* @className Action
* @author jy
* @date 2014年10月12日
* @since JDK 1.7
* @see
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Action {
MessageType msgType();
EventType[] eventType() default {};
}
@@ -1,18 +0,0 @@
package com.foxinmy.weixin4j.mp.mapping;
import org.dom4j.DocumentException;
import com.foxinmy.weixin4j.mp.action.WeixinAction;
/**
* 可扩展的Mapping接口
*
* @className ActionMapping
* @author jy
* @date 2014年10月28日
* @since JDK 1.7
* @see
*/
public interface ActionMapping {
public WeixinAction getAction(String xmlMsg) throws DocumentException;
}
@@ -1,59 +0,0 @@
package com.foxinmy.weixin4j.mp.mapping;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.dom4j.DocumentException;
import com.foxinmy.weixin4j.mp.action.WeixinAction;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
import com.foxinmy.weixin4j.util.ClassUtil;
/**
* 注解实现的Mapping
*
* @className AnnotationActionMapping
* @author jy
* @date 2014年10月28日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.mp.mapping.Action
*/
public class AnnotationActionMapping extends AbstractActionMapping {
private final Map<String, WeixinAction> actionMap;
public AnnotationActionMapping() {
actionMap = new HashMap<String, WeixinAction>();
Set<Class<?>> weixinActions = ClassUtil.getClasses(WeixinAction.class
.getPackage());
for (Class<?> clazz : weixinActions) {
Action action = clazz.getAnnotation(Action.class);
if (action == null) {
continue;
}
WeixinAction weixinAction = null;
try {
weixinAction = (WeixinAction) clazz.newInstance();
} catch (Exception e) {
continue;
}
MessageType msgType = action.msgType();
EventType[] eventTypes = action.eventType();
if (eventTypes != null && eventTypes.length > 0) {
for (EventType e : eventTypes) {
actionMap.put(
(msgType.name() + "_" + e.name()).toLowerCase(),
weixinAction);
}
continue;
}
actionMap.put(msgType.name().toLowerCase(), weixinAction);
}
}
public WeixinAction getAction(String xmlMsg) throws DocumentException {
String key = getMappingKey(xmlMsg);
return actionMap.get(key);
}
}
@@ -1 +0,0 @@
action与消息的mapping实现
@@ -1,133 +0,0 @@
package com.foxinmy.weixin4j.mp.model;
import io.netty.handler.codec.http.HttpMethod;
import java.io.Serializable;
import com.foxinmy.weixin4j.mp.type.EncryptType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
@XStreamAlias("xml")
public class HttpWeixinMessage implements Serializable {
private static final long serialVersionUID = -9157395300510879866L;
// 以下字段是加密方式为「安全模式」时的参数
@XStreamAlias("ToUserName")
private String toUserName;
@XStreamAlias("Encrypt")
private String encryptContent;
private EncryptType encryptType;
private String msgSignature;
// 以下字段每次被动消息时都会带上
private String echoStr;
private String timeStamp;
private String nonce;
private String signature;
private String token;
// xml消息主体
private String xmlContent;
// request method
private HttpMethod method;
public String getToUserName() {
return toUserName;
}
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
}
public String getEncryptContent() {
return encryptContent;
}
public void setEncryptContent(String encryptContent) {
this.encryptContent = encryptContent;
}
public EncryptType getEncryptType() {
return encryptType;
}
public void setEncryptType(EncryptType encryptType) {
this.encryptType = encryptType;
}
public String getMsgSignature() {
return msgSignature;
}
public void setMsgSignature(String msgSignature) {
this.msgSignature = msgSignature;
}
public String getEchoStr() {
return echoStr;
}
public void setEchoStr(String echoStr) {
this.echoStr = echoStr;
}
public String getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(String timeStamp) {
this.timeStamp = timeStamp;
}
public String getNonce() {
return nonce;
}
public void setNonce(String nonce) {
this.nonce = nonce;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getXmlContent() {
return xmlContent;
}
public void setXmlContent(String xmlContent) {
this.xmlContent = xmlContent;
}
public HttpMethod getMethod() {
return method;
}
public void setMethod(HttpMethod method) {
this.method = method;
}
@Override
public String toString() {
return "HttpMessage [toUserName=" + toUserName + ", encryptContent="
+ encryptContent + ", encryptType=" + encryptType
+ ", msgSignature=" + msgSignature + ", echoStr=" + echoStr
+ ", timeStamp=" + timeStamp + ", nonce=" + nonce
+ ", signature=" + signature + ", token=" + token
+ ", xmlContent=" + xmlContent + ", method=" + method + "]";
}
}
@@ -14,8 +14,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.model.HttpWeixinMessage;
import com.foxinmy.weixin4j.mp.type.EncryptType;
import com.foxinmy.weixin4j.response.HttpWeixinMessage;
import com.foxinmy.weixin4j.type.EncryptType;
import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.MessageUtil;
import com.foxinmy.weixin4j.xml.XStream;
@@ -43,7 +43,7 @@ public class WeixinMessageDecoder extends
if (StringUtils.isNotBlank(xmlContent)) {
message = XStream.get(xmlContent, HttpWeixinMessage.class);
}
message.setMethod(req.getMethod());
message.setMethod(req.getMethod().name());
QueryStringDecoder queryDecoder = new QueryStringDecoder(req.getUri(),
true);
log.info("\n=================receive request=================");
@@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.mp.server;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.handler.codec.http.HttpResponse;
import java.util.HashMap;
import java.util.List;
@@ -12,8 +11,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.message.ResponseMessage;
import com.foxinmy.weixin4j.mp.util.HttpUtil;
import com.foxinmy.weixin4j.response.ResponseMessage;
import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.DateUtil;
import com.foxinmy.weixin4j.util.MessageUtil;
@@ -33,7 +32,8 @@ import com.thoughtworks.xstream.mapper.DefaultMapper;
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E5%85%A5%E6%8C%87%E5%BC%95">加密接入指引</a>
*/
public class WeixinMessageEncoder extends MessageToMessageEncoder<ResponseMessage> {
public class WeixinMessageEncoder extends
MessageToMessageEncoder<ResponseMessage> {
private final Logger log = LoggerFactory.getLogger(getClass());
protected final static XStream mapXstream = XStream.get();
static {
@@ -51,8 +51,8 @@ public class WeixinMessageEncoder extends MessageToMessageEncoder<ResponseMessag
String timestamp = DateUtil.timestamp2string();
String encrtypt = MessageUtil.aesEncrypt(mpAccount.getId(),
mpAccount.getEncodingAesKey(), xmlContent);
String msgSignature = MessageUtil.signature(mpAccount.getToken(), nonce,
timestamp, encrtypt);
String msgSignature = MessageUtil.signature(mpAccount.getToken(),
nonce, timestamp, encrtypt);
Map<String, String> map = new HashMap<String, String>();
map.put("Encrypt", encrtypt);
map.put("MsgSignature", msgSignature);
@@ -60,12 +60,9 @@ public class WeixinMessageEncoder extends MessageToMessageEncoder<ResponseMessag
map.put("Nonce", nonce);
String content = mapXstream.toXML(map);
HttpResponse httpResponse = HttpUtil
.createWeixinMessageResponse(content);
out.add(httpResponse);
out.add(HttpUtil.createWeixinMessageResponse(content, null));
log.info("\n=================aes encrtypt out=================");
log.info("{}", map);
log.info("{}", content);
}
}
@@ -4,23 +4,24 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import org.apache.http.entity.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.mp.action.WeixinAction;
import com.foxinmy.weixin4j.mp.mapping.ActionMapping;
import com.foxinmy.weixin4j.mp.message.ResponseMessage;
import com.foxinmy.weixin4j.mp.model.HttpWeixinMessage;
import com.foxinmy.weixin4j.mp.type.EncryptType;
import com.foxinmy.weixin4j.action.WeixinAction;
import com.foxinmy.weixin4j.action.mapping.ActionMapping;
import com.foxinmy.weixin4j.mp.util.HttpUtil;
import com.foxinmy.weixin4j.response.HttpWeixinMessage;
import com.foxinmy.weixin4j.response.ResponseMessage;
import com.foxinmy.weixin4j.type.EncryptType;
import com.foxinmy.weixin4j.util.MessageUtil;
/**
* 微信被动消息处理类
*
* @className WeixinServerHandler
* @author jy
* @date 2014年11月16日
@@ -53,16 +54,15 @@ public class WeixinServerHandler extends
HttpWeixinMessage httpMessage) throws Exception {
log.info("\n=================message in=================\n{}",
httpMessage);
boolean isGet = httpMessage.getMethod().equals(HttpMethod.GET.name());
boolean validate = false;
if (httpMessage.getMethod() == HttpMethod.GET
|| httpMessage.getEncryptType() == EncryptType.RAW) {
if (isGet || httpMessage.getEncryptType() == EncryptType.RAW) {
validate = MessageUtil.signature(httpMessage.getToken(),
httpMessage.getTimeStamp(), httpMessage.getNonce()).equals(
httpMessage.getSignature());
if (httpMessage.getMethod() == HttpMethod.GET && validate) {
HttpResponse httpResponse = HttpUtil
.createWeixinMessageResponse(httpMessage.getEchoStr());
ctx.write(httpResponse);
if (isGet && validate) {
ctx.write(HttpUtil.createWeixinMessageResponse(
httpMessage.getEchoStr(), ContentType.TEXT_PLAIN));
return;
}
} else {
@@ -88,15 +88,13 @@ public class WeixinServerHandler extends
log.info("\n=================message out=================\n{}",
response);
if (response == null) {
HttpResponse httpResponse = HttpUtil
.createWeixinMessageResponse("");
ctx.write(httpResponse);
ctx.write(HttpUtil.createWeixinMessageResponse("",
ContentType.TEXT_PLAIN));
return;
}
if (httpMessage.getEncryptType() == EncryptType.RAW) {
HttpResponse httpResponse = HttpUtil
.createWeixinMessageResponse(response.toXml());
ctx.write(httpResponse);
ctx.write(HttpUtil.createWeixinMessageResponse(response.toXml(),
null));
} else {
ctx.write(response);
}
@@ -6,15 +6,17 @@ import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import com.foxinmy.weixin4j.mp.mapping.ActionMapping;
import com.foxinmy.weixin4j.mp.mapping.AnnotationActionMapping;
import com.foxinmy.weixin4j.action.mapping.ActionMapping;
import com.foxinmy.weixin4j.action.mapping.AnnotationActionMapping;
import com.foxinmy.weixin4j.mp.action.ImageAction;
public class WeixinServerInitializer extends ChannelInitializer<SocketChannel> {
private final ActionMapping actionMapping;
public WeixinServerInitializer() {
this.actionMapping = new AnnotationActionMapping();
this.actionMapping = new AnnotationActionMapping(
ImageAction.class.getPackage());
}
@Override
@@ -16,6 +16,7 @@ import io.netty.handler.codec.http.HttpResponse;
import java.util.Date;
import org.apache.http.Consts;
import org.apache.http.entity.ContentType;
/**
* HTTP工具类
@@ -28,7 +29,11 @@ import org.apache.http.Consts;
*/
public class HttpUtil {
public static HttpResponse createWeixinMessageResponse(String content) {
public static HttpResponse createWeixinMessageResponse(String content,
ContentType contentType) {
if (contentType == null) {
contentType = ContentType.APPLICATION_XML;
}
FullHttpResponse httpResponse = new DefaultFullHttpResponse(HTTP_1_1,
OK, Unpooled.copiedBuffer(content, Consts.UTF_8));
httpResponse.headers().set(CONTENT_TYPE,