在企业号工程上新增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
+5 -1
View File
@@ -33,4 +33,8 @@ weixin4j-base
* 2014-11-23
+ 新增企业号消息体以及用`Responseable`,`Notifyable`,`Massable`三个接口标记不同的可接受的消息类型
+ 新增企业号消息体以及用`Responseable`,`Notifyable`,`Massable`三个接口标记不同的可接受的消息类型
* 2014-11-24
+ 将Action跟Mapping基础类并入到项目
+5
View File
@@ -100,5 +100,10 @@
<artifactId>commons-codec</artifactId>
<version>${commons.codec.version}</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>${jaxen.version}</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,51 @@
package com.foxinmy.weixin4j.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.response.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.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;
}
}
@@ -0,0 +1,21 @@
package com.foxinmy.weixin4j.action;
import com.foxinmy.weixin4j.model.BaseMsg;
import com.foxinmy.weixin4j.response.ResponseMessage;
/**
* 回复一个空字符串 而不是一个XML结构体中content字段的内容为空
*
* @className BlankAction
* @author jy.hu
* @date 2014年10月2日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.action.AbstractAction
*/
public class BlankAction<M extends BaseMsg> extends AbstractAction<M> {
@Override
public ResponseMessage execute(M inMessage) {
return null;
}
}
@@ -0,0 +1,22 @@
package com.foxinmy.weixin4j.action;
import com.foxinmy.weixin4j.model.BaseMsg;
import com.foxinmy.weixin4j.msg.model.Text;
import com.foxinmy.weixin4j.response.ResponseMessage;
/**
* 调试输出用户消息
*
* @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);
}
}
@@ -0,0 +1,3 @@
消息处理接口,与weixin4j-*-server配合使用
如果只使用API包,则可以不关注
@@ -0,0 +1,20 @@
package com.foxinmy.weixin4j.action;
import org.dom4j.DocumentException;
import com.foxinmy.weixin4j.response.ResponseMessage;
/**
* 消息处理接口
*
* @className Action
* @author jy.hu
* @date 2014年10月2日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.action.AbstractAction
* @see com.foxinmy.weixin4j.action.BlankAction
* @see com.foxinmy.weixin4j.action.DebugAction
*/
public interface WeixinAction {
public ResponseMessage execute(String inMsg) throws DocumentException;
}
@@ -0,0 +1,29 @@
package com.foxinmy.weixin4j.action.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();
}
}
@@ -0,0 +1,26 @@
package com.foxinmy.weixin4j.action.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 ActionAnnotation {
MessageType msgType();
EventType[] eventType() default {};
}
@@ -0,0 +1,18 @@
package com.foxinmy.weixin4j.action.mapping;
import org.dom4j.DocumentException;
import com.foxinmy.weixin4j.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;
}
@@ -0,0 +1,58 @@
package com.foxinmy.weixin4j.action.mapping;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.dom4j.DocumentException;
import com.foxinmy.weixin4j.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.action.mapping.ActionAnnotation
*/
public class AnnotationActionMapping extends AbstractActionMapping {
private final Map<String, WeixinAction> actionMap;
public AnnotationActionMapping(Package actionPackage) {
actionMap = new HashMap<String, WeixinAction>();
Set<Class<?>> weixinActions = ClassUtil.getClasses(actionPackage);
for (Class<?> clazz : weixinActions) {
ActionAnnotation action = clazz.getAnnotation(ActionAnnotation.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);
}
}
@@ -0,0 +1,7 @@
消息处理与Action类的mapping对应(使用注解类的方式)
一般来说Action中应该有自己的实际业务处理类,那么上述方式可能不妥
推荐用org.springframework.context.ApplicationContext#getBeansWithAnnotation函数
当然,也可以重写AbstractActionMapping类实现自己的Mapping
@@ -26,6 +26,8 @@ public class BaseMsg implements Serializable {
private String msgType; // 消息类型
@XStreamAlias("MsgId")
private long msgId; // 消息ID
@XStreamAlias("AgentID")
private String agentId; // 企业号独有的应用ID
public BaseMsg() {
@@ -81,8 +83,8 @@ public class BaseMsg implements Serializable {
return msgId;
}
public void setMsgId(long msgId) {
this.msgId = msgId;
public String getAgentId() {
return agentId;
}
@Override
@@ -95,8 +97,8 @@ public class BaseMsg implements Serializable {
@Override
public String toString() {
return "BaseMsg [toUserName=" + toUserName + ", fromUserName="
+ fromUserName + ", createTime=" + createTime + ", msgType="
+ msgType + ", msgId=" + msgId + "]";
return "toUserName=" + toUserName + ", fromUserName=" + fromUserName
+ ", createTime=" + createTime + ", msgType=" + msgType
+ ", msgId=" + msgId + ", agentId=" + agentId;
}
}
@@ -12,7 +12,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E5.9B.BE.E7.89.87.E6.B6.88.E6.81.AF">图片消息</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E5.9B.BE.E7.89.87.E6.B6.88.E6.81.AF">订阅号、服务号的图片消息</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#image.E6.B6.88.E6.81.AF">企业号的图片消息</a>
*/
public class ImageMessage extends BaseMsg {
@@ -37,14 +39,7 @@ public class ImageMessage extends BaseMsg {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[ImageMessage ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType());
sb.append(" ,picUrl=").append(picUrl);
sb.append(" ,mediaId=").append(mediaId);
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();
return "ImageMessage [picUrl=" + picUrl + ", mediaId=" + mediaId + ", "
+ super.toString() + "]";
}
}
@@ -12,7 +12,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E9.93.BE.E6.8E.A5.E6.B6.88.E6.81.AF">链接消息</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E9.93.BE.E6.8E.A5.E6.B6.88.E6.81.AF">订阅号、服务号的链接消息</a>
*/
public class LinkMessage extends BaseMsg {
@@ -43,15 +43,7 @@ public class LinkMessage extends BaseMsg {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[LinkMessage ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType());
sb.append(" ,title=").append(title);
sb.append(" ,description=").append(description);
sb.append(" ,url=").append(url);
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();
return "LinkMessage [title=" + title + ", description=" + description
+ ", url=" + url + ", " + super.toString() + "]";
}
}
@@ -12,7 +12,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E6.B6.88.E6.81.AF">地理位置消息</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E6.B6.88.E6.81.AF">订阅号、服务号的地理位置消息</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#location.E6.B6.88.E6.81.AF">企业号的地理位置消息</a>
*/
public class LocationMessage extends BaseMsg {
@@ -53,17 +55,7 @@ public class LocationMessage extends BaseMsg {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[LocationMessage ,toUserName=")
.append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType());
sb.append(" ,location_X=").append(x);
sb.append(" ,location_Y=").append(y);
sb.append(" ,scale=").append(scale);
sb.append(" ,label=").append(label);
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();
return "LocationMessage [x=" + x + ", y=" + y + ", scale=" + scale
+ ", label=" + label + ", " + super.toString() + "]";
}
}
@@ -5,16 +5,16 @@ import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 文本消息(接收|回复)
* 文本消息
*
* @className TextMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">接收文本消息</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">订阅号、服务号的文本消息</a>
* @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#.E5.9B.9E.E5.A4.8D.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">回复文本消息</a>
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#text.E6.B6.88.E6.81.AF">企业号的文本消息</a>
*/
public class TextMessage extends BaseMsg {
@@ -31,19 +31,9 @@ public class TextMessage extends BaseMsg {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[TextMessage ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType());
sb.append(" ,content=").append(content);
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();
return "TextMessage [content=" + content + ", " + super.toString()
+ "]";
}
}
@@ -12,7 +12,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E8.A7.86.E9.A2.91.E6.B6.88.E6.81.AF">视频消息</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E8.A7.86.E9.A2.91.E6.B6.88.E6.81.AF">订阅号、服务号的视频消息</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#video.E6.B6.88.E6.81.AF">企业号的视频消息</a>
*/
public class VideoMessage extends BaseMsg {
@@ -37,14 +39,7 @@ public class VideoMessage extends BaseMsg {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[VideoMessage ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType());
sb.append(" ,mediaId=").append(mediaId);
sb.append(" ,thumbMediaId=").append(thumbMediaId);
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();
return "VideoMessage [mediaId=" + mediaId + ", thumbMediaId="
+ thumbMediaId + ", " + super.toString() + "]";
}
}
@@ -15,7 +15,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E8.AF.AD.E9.9F.B3.E6.B6.88.E6.81.AF">语音消息</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E8.AF.AD.E9.9F.B3.E6.B6.88.E6.81.AF">订阅号、服务号的语音消息</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#voice.E6.B6.88.E6.81.AF">企业号的语音消息</a>
*/
public class VoiceMessage extends BaseMsg {
@@ -47,15 +49,8 @@ public class VoiceMessage extends BaseMsg {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[VoiceMessage ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType());
sb.append(" ,mediaId=").append(mediaId);
sb.append(" ,format=").append(format);
sb.append(" ,recognition=").append(recognition);
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();
return "VoiceMessage [mediaId=" + mediaId + ", format=" + format
+ ", recognition=" + recognition + ", " + super.toString()
+ "]";
}
}
@@ -13,7 +13,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81">事件推送</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81">订阅号、服务号的事件推送</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6">企业号的事件消息</a>
*/
public class EventMessage extends BaseMsg {
@@ -31,19 +33,8 @@ public class EventMessage extends BaseMsg {
return eventType;
}
public void setEventType(EventType eventType) {
this.eventType = eventType;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[EventMessage ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType());
sb.append(" ,eventType=").append(eventType.name());
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();
return "eventType=" + eventType + ", " + super.toString();
}
}
@@ -11,7 +11,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E4.B8.8A.E6.8A.A5.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E4.BA.8B.E4.BB.B6">上报地理位置事件</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E4.B8.8A.E6.8A.A5.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E4.BA.8B.E4.BB.B6">订阅号、服务号的上报地理位置事件</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6#.E4.B8.8A.E6.8A.A5.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E4.BA.8B.E4.BB.B6">企业号的上报地理位置事件</a>
*/
public class LocationEventMessage extends EventMessage {
@@ -54,19 +54,9 @@ public class MassEventMessage extends EventMessage {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[MassEventMessage ,toUserName=").append(
super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType());
sb.append(" ,eventType=").append(super.getEventType().name());
sb.append(" ,status=").append(status);
sb.append(" ,totalCount=").append(totalCount);
sb.append(" ,filterCount=").append(filterCount);
sb.append(" ,sentCount=").append(sentCount);
sb.append(" ,errorCount=").append(errorCount);
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();
return "MassEventMessage [status=" + status + ", totalCount="
+ totalCount + ", filterCount=" + filterCount + ", sentCount="
+ sentCount + ", errorCount=" + errorCount + ", "
+ super.toString() + "]";
}
}
@@ -1,5 +1,6 @@
package com.foxinmy.weixin4j.msg.event;
import com.foxinmy.weixin4j.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
@@ -15,7 +16,11 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
public class ScanEventMessage extends EventMessage {
public ScanEventMessage() {
super(null);
super(EventType.scan);
}
public ScanEventMessage(EventType eventType) {
super(eventType);
}
private static final long serialVersionUID = 8078674062833071562L;
@@ -39,16 +44,7 @@ public class ScanEventMessage extends EventMessage {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[ScanEventMessage ,toUserName=").append(
super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType());
sb.append(" ,eventType=").append(super.getEventType().name());
sb.append(" ,eventKey=").append(eventKey);
sb.append(" ,ticket=").append(ticket);
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();
return "ScanEventMessage [eventKey=" + eventKey + ", ticket=" + ticket
+ ", " + super.toString() + "]";
}
}
@@ -1,31 +1,31 @@
package com.foxinmy.weixin4j.msg.event;
import com.foxinmy.weixin4j.type.EventType;
/**
* 关注/取消关注事件 <font color="red">包括直接关注与扫描关注</font>
* 关注/取消关注事件</br> <font color="red">包括直接关注与扫描关注</font>
*
* @className ScribeEventMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E5.85.B3.E6.B3.A8.2F.E5.8F.96.E6.B6.88.E5.85.B3.E6.B3.A8.E4.BA.8B.E4.BB.B6">关注/取消关注事件</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E5.85.B3.E6.B3.A8.2F.E5.8F.96.E6.B6.88.E5.85.B3.E6.B3.A8.E4.BA.8B.E4.BB.B6">订阅号、服务号的关注/取消关注事件</a>
* @see <a href="http://qydev.weixin.qq.com/wiki/index.php?title=%
* E5%85%B3%E6%B3%A8%E4%B8%
* 8E%E5%8F%96%E6%B6%88%E5%85%B3%E6%B3%A8#.E5.85.B3.E6.B3.A8.2F.E5.8F.96.E6.B6.88.E5.85.B3.E6.B3.A8.E4.BA.8B.E4.BB.B6.E7.9A.84.E6.8E.A8.E9.80.81">企业号的关注/取消关注
* 事 件 </a>
*/
public class ScribeEventMessage extends ScanEventMessage {
private static final long serialVersionUID = -6846321620262204915L;
public ScribeEventMessage() {
super(EventType.subscribe);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[ScribeEventMessage ,toUserName=").append(
super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType());
sb.append(" ,eventType=").append(super.getEventType().name());
sb.append(" ,eventKey=").append(super.getEventKey());
sb.append(" ,ticket=").append(super.getTicket());
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();
return "ScribeEventMessage [" + super.toString() + "]";
}
}
@@ -30,6 +30,7 @@ public class TemplatesendjobfinishMessage extends EventMessage {
@Override
public String toString() {
return "TemplatesendjobfinishMessage [status=" + status + "]";
return "TemplatesendjobfinishMessage [status=" + status + ", "
+ super.toString() + "]";
}
}
@@ -12,7 +12,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E7.82.B9.E5.87.BB.E8.8F.9C.E5.8D.95.E6.8B.89.E5.8F.96.E6.B6.88.E6.81.AF.E6.97.B6.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">菜单事件</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E7.82.B9.E5.87.BB.E8.8F.9C.E5.8D.95.E6.8B.89.E5.8F.96.E6.B6.88.E6.81.AF.E6.97.B6.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">订阅号、服务号的菜单事件</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6#.E4.B8.8A.E6.8A.A5.E8.8F.9C.E5.8D.95.E4.BA.8B.E4.BB.B6">企业号的菜单事件</a>
*/
public class MenuEventMessage extends EventMessage {
@@ -22,6 +24,10 @@ public class MenuEventMessage extends EventMessage {
super(EventType.click);
}
public MenuEventMessage(EventType eventType) {
super(eventType);
}
@XStreamAlias("EventKey")
private String eventKey; // 事件KEY值,与自定义菜单接口中KEY值对应
@@ -31,15 +37,6 @@ public class MenuEventMessage extends EventMessage {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[MenuEventMessage ,toUserName=").append(
super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType());
sb.append(" ,eventType=").append(super.getEventType().name());
sb.append(" ,eventKey=").append(eventKey);
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();
return "eventKey=" + eventKey + ", " + super.toString();
}
}
@@ -11,14 +11,15 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年9月30日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#location_select.EF.BC.9A.E5.BC.B9.E5.87.BA.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E9.80.89.E6.8B.A9.E5.99.A8.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">弹出地理位置选择事件推送</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#location_select.EF.BC.9A.E5.BC.B9.E5.87.BA.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E9.80.89.E6.8B.A9.E5.99.A8.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">订阅号、服务号的弹出地理位置选择事件推送</a>
* @see <a href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6#.E5.BC.B9.E5.87.BA.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E9.80.89.E6.8B.A9.E5.99.A8.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">企业号的弹出地理位置选择事件推送</a>
*/
public class MenuLocationEventMessage extends MenuEventMessage {
private static final long serialVersionUID = 145223888272819563L;
public MenuLocationEventMessage() {
super.setEventType(EventType.location_select);
super(EventType.location_select);
}
@XStreamAlias("SendLocationInfo")
@@ -69,6 +70,7 @@ public class MenuLocationEventMessage extends MenuEventMessage {
@Override
public String toString() {
return "MenuLocationEventMessage [locationInfo=" + locationInfo + "]";
return "MenuLocationEventMessage [locationInfo=" + locationInfo + ", "
+ super.toString() + "]";
}
}
@@ -12,7 +12,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年9月30日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#pic_sysphoto.EF.BC.9A.E5.BC.B9.E5.87.BA.E7.B3.BB.E7.BB.9F.E6.8B.8D.E7.85.A7.E5.8F.91.E5.9B.BE.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">弹出系统拍照发图的事件推送</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#pic_sysphoto.EF.BC.9A.E5.BC.B9.E5.87.BA.E7.B3.BB.E7.BB.9F.E6.8B.8D.E7.85.A7.E5.8F.91.E5.9B.BE.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">订阅号、服务号的系统发图的事件推送</a>
* @see <a href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6#.E5.BC.B9.E5.87.BA.E7.B3.BB.E7.BB.9F.E6.8B.8D.E7.85.A7.E5.8F.91.E5.9B.BE.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">企业号的系统发图的事件推送</a>
*/
public class MenuPhotoEventMessage extends MenuEventMessage {
@@ -58,6 +59,7 @@ public class MenuPhotoEventMessage extends MenuEventMessage {
@Override
public String toString() {
return "MenuPhotoEventMessage [pictureInfo=" + pictureInfo + "]";
return "MenuPhotoEventMessage [pictureInfo=" + pictureInfo + ", "
+ super.toString() + "]";
}
}
@@ -5,12 +5,14 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 扫码推事件(scancode_push|scancode_waitmsg)
*
* @className MenuScanPushEventMessage
* @className MenuScanEventMessage
* @author jy
* @date 2014年9月30日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#scancode_push.EF.BC.9A.E6.89.AB.E7.A0.81.E6.8E.A8.E4.BA.8B.E4.BB.B6.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">扫码推事件的事件推送</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#scancode_push.EF.BC.9A.E6.89.AB.E7.A0.81.E6.8E.A8.E4.BA.8B.E4.BB.B6.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">订阅号、服务号的扫码推事件</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6#.E6.89.AB.E7.A0.81.E6.8E.A8.E4.BA.8B.E4.BB.B6.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">企业号的的扫码推事件</a>
*/
public class MenuScanEventMessage extends MenuEventMessage {
@@ -45,7 +47,7 @@ public class MenuScanEventMessage extends MenuEventMessage {
@Override
public String toString() {
return "MenuScanPushEventMessage [scanInfo=" + scanInfo + "]";
return "MenuScanEventMessage [scanInfo=" + scanInfo + ", "
+ super.toString() + "]";
}
}
@@ -0,0 +1,131 @@
package com.foxinmy.weixin4j.response;
import java.io.Serializable;
import com.foxinmy.weixin4j.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 String 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 String getMethod() {
return method;
}
public void setMethod(String 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 + "]";
}
}
@@ -0,0 +1,115 @@
package com.foxinmy.weixin4j.response;
import org.apache.commons.lang3.StringUtils;
import com.foxinmy.weixin4j.model.BaseMsg;
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年11月22日
* @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>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%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.toString() + ", attach=" + attach
+ ", getToUserName()=" + getToUserName()
+ ", getFromUserName()=" + getFromUserName()
+ ", getCreateTime()=" + getCreateTime() + ", getMsgType()="
+ getMsgType() + "]";
}
}
@@ -0,0 +1,30 @@
package com.foxinmy.weixin4j.response;
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);
}
}
@@ -0,0 +1,13 @@
package com.foxinmy.weixin4j.type;
/**
* 消息加密类型
* @className EncryptType
* @author jy
* @date 2014年11月23日
* @since JDK 1.7
* @see
*/
public enum EncryptType {
RAW, AES
}