在企业号工程上新增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

View File

@ -12,11 +12,13 @@ weixin4j
`微信支付(公众号)` `微信支付(公众号)`
`netty构建服务器` `netty服务器&消息分发`
* **weixin4j-qy** * **weixin4j-qy**
`企业号API封装` `企业号API封装`
`netty服务器&消息分发`
更新LOG 更新LOG
------- -------
@ -108,6 +110,12 @@ weixin4j
+ **weixin4j-qy**: 新增`菜单管理`接口 + **weixin4j-qy**: 新增`菜单管理`接口
* 2014-11-24
+ **weixin4j-base**: 将Action跟Mapping基础类并入到项目
+ **weixin4j-qy**: 新增netty服务与消息分发
接下来 接下来
------ ------
* 企业号消息与事件 * 企业号消息与事件

View File

@ -33,4 +33,8 @@ weixin4j-base
* 2014-11-23 * 2014-11-23
+ 新增企业号消息体以及用`Responseable`,`Notifyable`,`Massable`三个接口标记不同的可接受的消息类型 + 新增企业号消息体以及用`Responseable`,`Notifyable`,`Massable`三个接口标记不同的可接受的消息类型
* 2014-11-24
+ 将Action跟Mapping基础类并入到项目

View File

@ -100,5 +100,10 @@
<artifactId>commons-codec</artifactId> <artifactId>commons-codec</artifactId>
<version>${commons.codec.version}</version> <version>${commons.codec.version}</version>
</dependency> </dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>${jaxen.version}</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.action; package com.foxinmy.weixin4j.action;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -6,7 +6,7 @@ import java.lang.reflect.Type;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;
import com.foxinmy.weixin4j.model.BaseMsg; import com.foxinmy.weixin4j.model.BaseMsg;
import com.foxinmy.weixin4j.mp.message.ResponseMessage; import com.foxinmy.weixin4j.response.ResponseMessage;
import com.foxinmy.weixin4j.util.MessageUtil; import com.foxinmy.weixin4j.util.MessageUtil;
import com.foxinmy.weixin4j.xml.XStream; import com.foxinmy.weixin4j.xml.XStream;
@ -17,7 +17,7 @@ import com.foxinmy.weixin4j.xml.XStream;
* @author jy * @author jy
* @date 2014年10月12日 * @date 2014年10月12日
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.mp.action.WeixinAction * @see com.foxinmy.weixin4j.action.WeixinAction
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public abstract class AbstractAction<M extends BaseMsg> implements public abstract class AbstractAction<M extends BaseMsg> implements

View File

@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action; package com.foxinmy.weixin4j.action;
import com.foxinmy.weixin4j.model.BaseMsg; import com.foxinmy.weixin4j.model.BaseMsg;
import com.foxinmy.weixin4j.mp.message.ResponseMessage; import com.foxinmy.weixin4j.response.ResponseMessage;
/** /**
* 回复一个空字符串 而不是一个XML结构体中content字段的内容为空 * 回复一个空字符串 而不是一个XML结构体中content字段的内容为空
@ -10,7 +10,7 @@ import com.foxinmy.weixin4j.mp.message.ResponseMessage;
* @author jy.hu * @author jy.hu
* @date 2014年10月2日 * @date 2014年10月2日
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.mp.action.AbstractAction * @see com.foxinmy.weixin4j.action.AbstractAction
*/ */
public class BlankAction<M extends BaseMsg> extends AbstractAction<M> { public class BlankAction<M extends BaseMsg> extends AbstractAction<M> {

View File

@ -1,8 +1,8 @@
package com.foxinmy.weixin4j.mp.action; package com.foxinmy.weixin4j.action;
import com.foxinmy.weixin4j.model.BaseMsg; import com.foxinmy.weixin4j.model.BaseMsg;
import com.foxinmy.weixin4j.mp.message.ResponseMessage;
import com.foxinmy.weixin4j.msg.model.Text; import com.foxinmy.weixin4j.msg.model.Text;
import com.foxinmy.weixin4j.response.ResponseMessage;
/** /**
* 调试输出用户消息 * 调试输出用户消息

View File

@ -0,0 +1,3 @@
消息处理接口,与weixin4j-*-server配合使用
如果只使用API包,则可以不关注

View File

@ -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;
}

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.mapping; package com.foxinmy.weixin4j.action.mapping;
import org.dom4j.Document; import org.dom4j.Document;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.mapping; package com.foxinmy.weixin4j.action.mapping;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -18,7 +18,7 @@ import com.foxinmy.weixin4j.type.MessageType;
*/ */
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Action { public @interface ActionAnnotation {
MessageType msgType(); MessageType msgType();

View File

@ -1,8 +1,8 @@
package com.foxinmy.weixin4j.mp.mapping; package com.foxinmy.weixin4j.action.mapping;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;
import com.foxinmy.weixin4j.mp.action.WeixinAction; import com.foxinmy.weixin4j.action.WeixinAction;
/** /**
* 可扩展的Mapping接口 * 可扩展的Mapping接口

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.mapping; package com.foxinmy.weixin4j.action.mapping;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -6,7 +6,7 @@ import java.util.Set;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;
import com.foxinmy.weixin4j.mp.action.WeixinAction; import com.foxinmy.weixin4j.action.WeixinAction;
import com.foxinmy.weixin4j.type.EventType; import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
import com.foxinmy.weixin4j.util.ClassUtil; import com.foxinmy.weixin4j.util.ClassUtil;
@ -18,17 +18,16 @@ import com.foxinmy.weixin4j.util.ClassUtil;
* @author jy * @author jy
* @date 2014年10月28日 * @date 2014年10月28日
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.mp.mapping.Action * @see com.foxinmy.weixin4j.action.mapping.ActionAnnotation
*/ */
public class AnnotationActionMapping extends AbstractActionMapping { public class AnnotationActionMapping extends AbstractActionMapping {
private final Map<String, WeixinAction> actionMap; private final Map<String, WeixinAction> actionMap;
public AnnotationActionMapping() { public AnnotationActionMapping(Package actionPackage) {
actionMap = new HashMap<String, WeixinAction>(); actionMap = new HashMap<String, WeixinAction>();
Set<Class<?>> weixinActions = ClassUtil.getClasses(WeixinAction.class Set<Class<?>> weixinActions = ClassUtil.getClasses(actionPackage);
.getPackage());
for (Class<?> clazz : weixinActions) { for (Class<?> clazz : weixinActions) {
Action action = clazz.getAnnotation(Action.class); ActionAnnotation action = clazz.getAnnotation(ActionAnnotation.class);
if (action == null) { if (action == null) {
continue; continue;
} }

View File

@ -0,0 +1,7 @@
消息处理与Action类的mapping对应(使用注解类的方式)
一般来说Action中应该有自己的实际业务处理类,那么上述方式可能不妥
推荐用org.springframework.context.ApplicationContext#getBeansWithAnnotation函数
当然,也可以重写AbstractActionMapping类实现自己的Mapping

View File

@ -26,6 +26,8 @@ public class BaseMsg implements Serializable {
private String msgType; // 消息类型 private String msgType; // 消息类型
@XStreamAlias("MsgId") @XStreamAlias("MsgId")
private long msgId; // 消息ID private long msgId; // 消息ID
@XStreamAlias("AgentID")
private String agentId; // 企业号独有的应用ID
public BaseMsg() { public BaseMsg() {
@ -81,8 +83,8 @@ public class BaseMsg implements Serializable {
return msgId; return msgId;
} }
public void setMsgId(long msgId) { public String getAgentId() {
this.msgId = msgId; return agentId;
} }
@Override @Override
@ -95,8 +97,8 @@ public class BaseMsg implements Serializable {
@Override @Override
public String toString() { public String toString() {
return "BaseMsg [toUserName=" + toUserName + ", fromUserName=" return "toUserName=" + toUserName + ", fromUserName=" + fromUserName
+ fromUserName + ", createTime=" + createTime + ", msgType=" + ", createTime=" + createTime + ", msgType=" + msgType
+ msgType + ", msgId=" + msgId + "]"; + ", msgId=" + msgId + ", agentId=" + agentId;
} }
} }

View File

@ -12,7 +12,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日 * @date 2014年4月6日
* @since JDK 1.7 * @since JDK 1.7
* @see <a * @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 { public class ImageMessage extends BaseMsg {
@ -37,14 +39,7 @@ public class ImageMessage extends BaseMsg {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); return "ImageMessage [picUrl=" + picUrl + ", mediaId=" + mediaId + ", "
sb.append("[ImageMessage ,toUserName=").append(super.getToUserName()); + super.toString() + "]";
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();
} }
} }

View File

@ -12,7 +12,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日 * @date 2014年4月6日
* @since JDK 1.7 * @since JDK 1.7
* @see <a * @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 { public class LinkMessage extends BaseMsg {
@ -43,15 +43,7 @@ public class LinkMessage extends BaseMsg {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); return "LinkMessage [title=" + title + ", description=" + description
sb.append("[LinkMessage ,toUserName=").append(super.getToUserName()); + ", url=" + url + ", " + super.toString() + "]";
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();
} }
} }

View File

@ -12,7 +12,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日 * @date 2014年4月6日
* @since JDK 1.7 * @since JDK 1.7
* @see <a * @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 { public class LocationMessage extends BaseMsg {
@ -53,17 +55,7 @@ public class LocationMessage extends BaseMsg {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); return "LocationMessage [x=" + x + ", y=" + y + ", scale=" + scale
sb.append("[LocationMessage ,toUserName=") + ", label=" + label + ", " + super.toString() + "]";
.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();
} }
} }

View File

@ -5,16 +5,16 @@ import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
/** /**
* 文本消息(接收|回复) * 文本消息
* *
* @className TextMessage * @className TextMessage
* @author jy.hu * @author jy.hu
* @date 2014年4月6日 * @date 2014年4月6日
* @since JDK 1.7 * @since JDK 1.7
* @see <a * @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 * @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 { public class TextMessage extends BaseMsg {
@ -31,19 +31,9 @@ public class TextMessage extends BaseMsg {
return content; return content;
} }
public void setContent(String content) {
this.content = content;
}
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); return "TextMessage [content=" + content + ", " + super.toString()
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();
} }
} }

View File

@ -12,7 +12,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日 * @date 2014年4月6日
* @since JDK 1.7 * @since JDK 1.7
* @see <a * @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 { public class VideoMessage extends BaseMsg {
@ -37,14 +39,7 @@ public class VideoMessage extends BaseMsg {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); return "VideoMessage [mediaId=" + mediaId + ", thumbMediaId="
sb.append("[VideoMessage ,toUserName=").append(super.getToUserName()); + thumbMediaId + ", " + super.toString() + "]";
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();
} }
} }

View File

@ -15,7 +15,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日 * @date 2014年4月6日
* @since JDK 1.7 * @since JDK 1.7
* @see <a * @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 { public class VoiceMessage extends BaseMsg {
@ -47,15 +49,8 @@ public class VoiceMessage extends BaseMsg {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); return "VoiceMessage [mediaId=" + mediaId + ", format=" + format
sb.append("[VoiceMessage ,toUserName=").append(super.getToUserName()); + ", recognition=" + recognition + ", " + super.toString()
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();
} }
} }

View File

@ -13,7 +13,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日 * @date 2014年4月6日
* @since JDK 1.7 * @since JDK 1.7
* @see <a * @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 { public class EventMessage extends BaseMsg {
@ -31,19 +33,8 @@ public class EventMessage extends BaseMsg {
return eventType; return eventType;
} }
public void setEventType(EventType eventType) {
this.eventType = eventType;
}
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); return "eventType=" + eventType + ", " + super.toString();
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();
} }
} }

View File

@ -11,7 +11,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日 * @date 2014年4月6日
* @since JDK 1.7 * @since JDK 1.7
* @see <a * @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 { public class LocationEventMessage extends EventMessage {

View File

@ -54,19 +54,9 @@ public class MassEventMessage extends EventMessage {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); return "MassEventMessage [status=" + status + ", totalCount="
sb.append("[MassEventMessage ,toUserName=").append( + totalCount + ", filterCount=" + filterCount + ", sentCount="
super.getToUserName()); + sentCount + ", errorCount=" + errorCount + ", "
sb.append(" ,fromUserName=").append(super.getFromUserName()); + super.toString() + "]";
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();
} }
} }

View File

@ -1,5 +1,6 @@
package com.foxinmy.weixin4j.msg.event; package com.foxinmy.weixin4j.msg.event;
import com.foxinmy.weixin4j.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
/** /**
@ -15,7 +16,11 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
public class ScanEventMessage extends EventMessage { public class ScanEventMessage extends EventMessage {
public ScanEventMessage() { public ScanEventMessage() {
super(null); super(EventType.scan);
}
public ScanEventMessage(EventType eventType) {
super(eventType);
} }
private static final long serialVersionUID = 8078674062833071562L; private static final long serialVersionUID = 8078674062833071562L;
@ -39,16 +44,7 @@ public class ScanEventMessage extends EventMessage {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); return "ScanEventMessage [eventKey=" + eventKey + ", ticket=" + ticket
sb.append("[ScanEventMessage ,toUserName=").append( + ", " + super.toString() + "]";
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();
} }
} }

View File

@ -1,31 +1,31 @@
package com.foxinmy.weixin4j.msg.event; package com.foxinmy.weixin4j.msg.event;
import com.foxinmy.weixin4j.type.EventType;
/** /**
* 关注/取消关注事件 <font color="red">包括直接关注与扫描关注</font> * 关注/取消关注事件</br> <font color="red">包括直接关注与扫描关注</font>
* *
* @className ScribeEventMessage * @className ScribeEventMessage
* @author jy.hu * @author jy.hu
* @date 2014年4月6日 * @date 2014年4月6日
* @since JDK 1.7 * @since JDK 1.7
* @see <a * @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 { public class ScribeEventMessage extends ScanEventMessage {
private static final long serialVersionUID = -6846321620262204915L; private static final long serialVersionUID = -6846321620262204915L;
public ScribeEventMessage() {
super(EventType.subscribe);
}
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); return "ScribeEventMessage [" + super.toString() + "]";
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();
} }
} }

View File

@ -30,6 +30,7 @@ public class TemplatesendjobfinishMessage extends EventMessage {
@Override @Override
public String toString() { public String toString() {
return "TemplatesendjobfinishMessage [status=" + status + "]"; return "TemplatesendjobfinishMessage [status=" + status + ", "
+ super.toString() + "]";
} }
} }

View File

@ -12,7 +12,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年4月6日 * @date 2014年4月6日
* @since JDK 1.7 * @since JDK 1.7
* @see <a * @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 { public class MenuEventMessage extends EventMessage {
@ -22,6 +24,10 @@ public class MenuEventMessage extends EventMessage {
super(EventType.click); super(EventType.click);
} }
public MenuEventMessage(EventType eventType) {
super(eventType);
}
@XStreamAlias("EventKey") @XStreamAlias("EventKey")
private String eventKey; // 事件KEY值与自定义菜单接口中KEY值对应 private String eventKey; // 事件KEY值与自定义菜单接口中KEY值对应
@ -31,15 +37,6 @@ public class MenuEventMessage extends EventMessage {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); return "eventKey=" + eventKey + ", " + super.toString();
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();
} }
} }

View File

@ -11,14 +11,15 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年9月30日 * @date 2014年9月30日
* @since JDK 1.7 * @since JDK 1.7
* @see <a * @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 { public class MenuLocationEventMessage extends MenuEventMessage {
private static final long serialVersionUID = 145223888272819563L; private static final long serialVersionUID = 145223888272819563L;
public MenuLocationEventMessage() { public MenuLocationEventMessage() {
super.setEventType(EventType.location_select); super(EventType.location_select);
} }
@XStreamAlias("SendLocationInfo") @XStreamAlias("SendLocationInfo")
@ -69,6 +70,7 @@ public class MenuLocationEventMessage extends MenuEventMessage {
@Override @Override
public String toString() { public String toString() {
return "MenuLocationEventMessage [locationInfo=" + locationInfo + "]"; return "MenuLocationEventMessage [locationInfo=" + locationInfo + ", "
+ super.toString() + "]";
} }
} }

View File

@ -12,7 +12,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @date 2014年9月30日 * @date 2014年9月30日
* @since JDK 1.7 * @since JDK 1.7
* @see <a * @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 { public class MenuPhotoEventMessage extends MenuEventMessage {
@ -58,6 +59,7 @@ public class MenuPhotoEventMessage extends MenuEventMessage {
@Override @Override
public String toString() { public String toString() {
return "MenuPhotoEventMessage [pictureInfo=" + pictureInfo + "]"; return "MenuPhotoEventMessage [pictureInfo=" + pictureInfo + ", "
+ super.toString() + "]";
} }
} }

View File

@ -5,12 +5,14 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
/** /**
* 扫码推事件(scancode_push|scancode_waitmsg) * 扫码推事件(scancode_push|scancode_waitmsg)
* *
* @className MenuScanPushEventMessage * @className MenuScanEventMessage
* @author jy * @author jy
* @date 2014年9月30日 * @date 2014年9月30日
* @since JDK 1.7 * @since JDK 1.7
* @see <a * @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 { public class MenuScanEventMessage extends MenuEventMessage {
@ -45,7 +47,7 @@ public class MenuScanEventMessage extends MenuEventMessage {
@Override @Override
public String toString() { public String toString() {
return "MenuScanPushEventMessage [scanInfo=" + scanInfo + "]"; return "MenuScanEventMessage [scanInfo=" + scanInfo + ", "
+ super.toString() + "]";
} }
} }

View File

@ -1,10 +1,8 @@
package com.foxinmy.weixin4j.mp.model; package com.foxinmy.weixin4j.response;
import io.netty.handler.codec.http.HttpMethod;
import java.io.Serializable; import java.io.Serializable;
import com.foxinmy.weixin4j.mp.type.EncryptType; import com.foxinmy.weixin4j.type.EncryptType;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
@XStreamAlias("xml") @XStreamAlias("xml")
@ -31,7 +29,7 @@ public class HttpWeixinMessage implements Serializable {
private String xmlContent; private String xmlContent;
// request method // request method
private HttpMethod method; private String method;
public String getToUserName() { public String getToUserName() {
return toUserName; return toUserName;
@ -113,11 +111,11 @@ public class HttpWeixinMessage implements Serializable {
this.xmlContent = xmlContent; this.xmlContent = xmlContent;
} }
public HttpMethod getMethod() { public String getMethod() {
return method; return method;
} }
public void setMethod(HttpMethod method) { public void setMethod(String method) {
this.method = method; this.method = method;
} }

View File

@ -1,9 +1,8 @@
package com.foxinmy.weixin4j.mp.message; package com.foxinmy.weixin4j.response;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import com.foxinmy.weixin4j.model.BaseMsg; 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.Article;
import com.foxinmy.weixin4j.msg.model.Base; import com.foxinmy.weixin4j.msg.model.Base;
import com.foxinmy.weixin4j.msg.model.News; import com.foxinmy.weixin4j.msg.model.News;
@ -21,7 +20,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* *
* @className ResponseMessage * @className ResponseMessage
* @author jy.hu * @author jy.hu
* @date 2014年4月6 * @date 2014年11月22
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.model.Text * @see com.foxinmy.weixin4j.msg.model.Text
* @see com.foxinmy.weixin4j.msg.model.Image * @see com.foxinmy.weixin4j.msg.model.Image
@ -32,7 +31,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @see com.foxinmy.weixin4j.msg.model.Trans * @see com.foxinmy.weixin4j.msg.model.Trans
* @see <a href= * @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" * "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> * >订阅号服务号的被动响应消息</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") @XStreamAlias("xml")
public class ResponseMessage extends BaseMsg { public class ResponseMessage extends BaseMsg {
@ -105,8 +106,9 @@ public class ResponseMessage extends BaseMsg {
@Override @Override
public String toString() { public String toString() {
return "ResponseMessage [box=" + box + ", getToUserName()=" return "ResponseMessage [" + box.toString() + ", attach=" + attach
+ getToUserName() + ", getFromUserName()=" + getFromUserName() + ", getToUserName()=" + getToUserName()
+ ", getFromUserName()=" + getFromUserName()
+ ", getCreateTime()=" + getCreateTime() + ", getMsgType()=" + ", getCreateTime()=" + getCreateTime() + ", getMsgType()="
+ getMsgType() + "]"; + getMsgType() + "]";
} }

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.converter; package com.foxinmy.weixin4j.response;
import com.foxinmy.weixin4j.msg.model.Text; import com.foxinmy.weixin4j.msg.model.Text;
import com.thoughtworks.xstream.converters.SingleValueConverter; import com.thoughtworks.xstream.converters.SingleValueConverter;

View File

@ -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
}

View File

@ -47,7 +47,7 @@ weixin.properties说明
示例(properties中换行用右斜杆\\) 示例(properties中换行用右斜杆\\)
> account={"id":"appId","secret":"appSecret", > account={"id":"appId","secret":"appSecret",
> "token":"开放者的token 必须","openId":"公众号的openid 非必须", > "token":"开放者的token","openId":"公众号的openid 非必须",
> "encodingAesKey":"公众号设置了加密方式且为「安全模式」需要填入", > "encodingAesKey":"公众号设置了加密方式且为「安全模式」需要填入",
> "mchId":"V3.x版本下的微信商户号", > "mchId":"V3.x版本下的微信商户号",
> "partnerId":"财付通的商户号","partnerKey":"财付通商户权限密钥Key", > "partnerId":"财付通的商户号","partnerKey":"财付通商户权限密钥Key",

View File

@ -24,11 +24,6 @@
</plugins> </plugins>
</build> </build>
<dependencies> <dependencies>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>${jaxen.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.apache.poi</groupId> <groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId> <artifactId>poi</artifactId>

View File

@ -42,10 +42,10 @@ import com.foxinmy.weixin4j.http.SSLHttpRequest;
import com.foxinmy.weixin4j.http.XmlResult; import com.foxinmy.weixin4j.http.XmlResult;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinMpAccount; 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.ApiResult;
import com.foxinmy.weixin4j.mp.payment.PayUtil; import com.foxinmy.weixin4j.mp.payment.PayUtil;
import com.foxinmy.weixin4j.mp.payment.Refund; 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.RefundResult;
import com.foxinmy.weixin4j.mp.payment.v2.Order; import com.foxinmy.weixin4j.mp.payment.v2.Order;
import com.foxinmy.weixin4j.mp.type.BillType; import com.foxinmy.weixin4j.mp.type.BillType;

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.converter; package com.foxinmy.weixin4j.mp.payment;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.HashMap; import java.util.HashMap;
@ -9,8 +9,6 @@ import java.util.Map.Entry;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; 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.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.MarshallingContext;

View File

@ -1,5 +0,0 @@
package com.foxinmy.weixin4j.mp.type;
public enum EncryptType {
RAW, AES
}

View File

@ -5,7 +5,6 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import com.foxinmy.weixin4j.model.BaseMsg; import com.foxinmy.weixin4j.model.BaseMsg;
import com.foxinmy.weixin4j.mp.message.ResponseMessage;
import com.foxinmy.weixin4j.msg.TextMessage; import com.foxinmy.weixin4j.msg.TextMessage;
import com.foxinmy.weixin4j.msg.model.Image; import com.foxinmy.weixin4j.msg.model.Image;
import com.foxinmy.weixin4j.msg.model.Music; 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.Trans;
import com.foxinmy.weixin4j.msg.model.Video; import com.foxinmy.weixin4j.msg.model.Video;
import com.foxinmy.weixin4j.msg.model.Voice; import com.foxinmy.weixin4j.msg.model.Voice;
import com.foxinmy.weixin4j.response.ResponseMessage;
/** /**
* 发送消息格式测试 * 发送消息格式测试

View File

@ -27,7 +27,7 @@ weixin4j-mp-server
示例(properties中换行用右斜杆\\) 示例(properties中换行用右斜杆\\)
> account={"id":"appId","secret":"appSecret", > account={"id":"appId","secret":"appSecret",
> "token":"开放者的token 必须","openId":"公众号的openid 非必须", > "token":"开放者的token","openId":"公众号的openid 非必须",
> "encodingAesKey":"公众号设置了加密方式且为「安全模式」时需要填入", > "encodingAesKey":"公众号设置了加密方式且为「安全模式」时需要填入",
> "mchId":"V3.x版本下的微信商户号", > "mchId":"V3.x版本下的微信商户号",
> "partnerId":"财付通的商户号","partnerKey":"财付通商户权限密钥Key", > "partnerId":"财付通的商户号","partnerKey":"财付通商户权限密钥Key",

View File

@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.mp.action; 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.msg.ImageMessage;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -13,7 +14,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.ImageMessage * @see com.foxinmy.weixin4j.msg.ImageMessage
*/ */
@Action(msgType = MessageType.image) @ActionAnnotation(msgType = MessageType.image)
public class ImageAction extends DebugAction<ImageMessage> { public class ImageAction extends DebugAction<ImageMessage> {
} }

View File

@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.mp.action; 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.msg.LinkMessage;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -13,7 +14,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.LinkMessage * @see com.foxinmy.weixin4j.msg.LinkMessage
*/ */
@Action(msgType = MessageType.link) @ActionAnnotation(msgType = MessageType.link)
public class LinkAction extends DebugAction<LinkMessage> { public class LinkAction extends DebugAction<LinkMessage> {
} }

View File

@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.mp.action; 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.msg.LocationMessage;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -13,7 +14,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.LocationMessage * @see com.foxinmy.weixin4j.msg.LocationMessage
*/ */
@Action(msgType = MessageType.location) @ActionAnnotation(msgType = MessageType.location)
public class LocationAction extends DebugAction<LocationMessage> { public class LocationAction extends DebugAction<LocationMessage> {
} }

View File

@ -1,9 +1,10 @@
package com.foxinmy.weixin4j.mp.action; package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.mapping.Action; import com.foxinmy.weixin4j.action.AbstractAction;
import com.foxinmy.weixin4j.mp.message.ResponseMessage; import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.TextMessage; import com.foxinmy.weixin4j.msg.TextMessage;
import com.foxinmy.weixin4j.msg.model.Text; import com.foxinmy.weixin4j.msg.model.Text;
import com.foxinmy.weixin4j.response.ResponseMessage;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
/** /**
@ -15,7 +16,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.TextMessage * @see com.foxinmy.weixin4j.msg.TextMessage
*/ */
@Action(msgType = MessageType.text) @ActionAnnotation(msgType = MessageType.text)
public class TextAction extends AbstractAction<TextMessage> { public class TextAction extends AbstractAction<TextMessage> {
@Override @Override

View File

@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.mp.action; 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.msg.VideoMessage;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -13,7 +14,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.VideoMessage * @see com.foxinmy.weixin4j.msg.VideoMessage
*/ */
@Action(msgType = MessageType.video) @ActionAnnotation(msgType = MessageType.video)
public class VideoAction extends DebugAction<VideoMessage> { public class VideoAction extends DebugAction<VideoMessage> {
} }

View File

@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.mp.action; 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.msg.VoiceMessage;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -13,7 +14,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.VoiceMessage * @see com.foxinmy.weixin4j.msg.VoiceMessage
*/ */
@Action(msgType = MessageType.voice) @ActionAnnotation(msgType = MessageType.voice)
public class VoiceAction extends DebugAction<VoiceMessage> { public class VoiceAction extends DebugAction<VoiceMessage> {
} }

View File

@ -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;
}

View File

@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event; package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction; import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action; import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.LocationEventMessage; import com.foxinmy.weixin4j.msg.event.LocationEventMessage;
import com.foxinmy.weixin4j.type.EventType; import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.LocationEventMessage * @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> { public class LocationAction extends DebugAction<LocationEventMessage> {
} }

View File

@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event; package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction; import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action; import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.MassEventMessage; import com.foxinmy.weixin4j.msg.event.MassEventMessage;
import com.foxinmy.weixin4j.type.EventType; import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.MassEventMessage * @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> { public class MassSendAction extends DebugAction<MassEventMessage> {
} }

View File

@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event; package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction; import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action; import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage; import com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage;
import com.foxinmy.weixin4j.type.EventType; import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage * @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> { public class MenuClickAction extends DebugAction<MenuEventMessage> {
} }

View File

@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event; package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction; import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action; import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.menu.MenuLocationEventMessage; import com.foxinmy.weixin4j.msg.event.menu.MenuLocationEventMessage;
import com.foxinmy.weixin4j.type.EventType; import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuLocationEventMessage * @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> { public class MenuLocationAction extends DebugAction<MenuLocationEventMessage> {
} }

View File

@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event; package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction; import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action; import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage; import com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage;
import com.foxinmy.weixin4j.type.EventType; import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage * @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_photo_or_album, EventType.pic_sysphoto,
EventType.pic_weixin }) EventType.pic_weixin })
public class MenuPhotoAction extends DebugAction<MenuPhotoEventMessage> { public class MenuPhotoAction extends DebugAction<MenuPhotoEventMessage> {

View File

@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event; package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction; import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action; import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage; import com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage;
import com.foxinmy.weixin4j.type.EventType; import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage * @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 }) EventType.scancode_waitmsg })
public class MenuScanAction extends DebugAction<MenuScanEventMessage> { public class MenuScanAction extends DebugAction<MenuScanEventMessage> {

View File

@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event; package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction; import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action; import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage; import com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage;
import com.foxinmy.weixin4j.type.EventType; import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage * @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> { public class MenuViewAction extends DebugAction<MenuEventMessage> {
} }

View File

@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event; package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction; import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action; import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.ScanEventMessage; import com.foxinmy.weixin4j.msg.event.ScanEventMessage;
import com.foxinmy.weixin4j.type.EventType; import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.ScanEventMessage * @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> { public class ScanAction extends DebugAction<ScanEventMessage> {
} }

View File

@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event; package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction; import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action; import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.ScribeEventMessage; import com.foxinmy.weixin4j.msg.event.ScribeEventMessage;
import com.foxinmy.weixin4j.type.EventType; import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.ScribeEventMessage * @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> { public class SubscribeAction extends DebugAction<ScribeEventMessage> {
} }

View File

@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event; package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction; import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action; import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage; import com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage;
import com.foxinmy.weixin4j.type.EventType; import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage * @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 public class TemplateSendAction extends
DebugAction<TemplatesendjobfinishMessage> { DebugAction<TemplatesendjobfinishMessage> {

View File

@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.action.event; package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction; import com.foxinmy.weixin4j.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action; import com.foxinmy.weixin4j.action.mapping.ActionAnnotation;
import com.foxinmy.weixin4j.msg.event.ScribeEventMessage; import com.foxinmy.weixin4j.msg.event.ScribeEventMessage;
import com.foxinmy.weixin4j.type.EventType; import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.type.MessageType;
* @since JDK 1.7 * @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.ScribeEventMessage * @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> { public class UnsubscribeAction extends DebugAction<ScribeEventMessage> {
} }

View File

@ -1 +0,0 @@
action与消息的mapping实现

View File

@ -14,8 +14,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.model.WeixinMpAccount; import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.model.HttpWeixinMessage; import com.foxinmy.weixin4j.response.HttpWeixinMessage;
import com.foxinmy.weixin4j.mp.type.EncryptType; import com.foxinmy.weixin4j.type.EncryptType;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.MessageUtil; import com.foxinmy.weixin4j.util.MessageUtil;
import com.foxinmy.weixin4j.xml.XStream; import com.foxinmy.weixin4j.xml.XStream;
@ -43,7 +43,7 @@ public class WeixinMessageDecoder extends
if (StringUtils.isNotBlank(xmlContent)) { if (StringUtils.isNotBlank(xmlContent)) {
message = XStream.get(xmlContent, HttpWeixinMessage.class); message = XStream.get(xmlContent, HttpWeixinMessage.class);
} }
message.setMethod(req.getMethod()); 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=================");

View File

@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.mp.server;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.handler.codec.http.HttpResponse;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -12,8 +11,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.model.WeixinMpAccount; import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.message.ResponseMessage;
import com.foxinmy.weixin4j.mp.util.HttpUtil; import com.foxinmy.weixin4j.mp.util.HttpUtil;
import com.foxinmy.weixin4j.response.ResponseMessage;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.DateUtil; import com.foxinmy.weixin4j.util.DateUtil;
import com.foxinmy.weixin4j.util.MessageUtil; import com.foxinmy.weixin4j.util.MessageUtil;
@ -33,7 +32,8 @@ import com.thoughtworks.xstream.mapper.DefaultMapper;
* @see <a * @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> * 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()); private final Logger log = LoggerFactory.getLogger(getClass());
protected final static XStream mapXstream = XStream.get(); protected final static XStream mapXstream = XStream.get();
static { static {
@ -51,8 +51,8 @@ public class WeixinMessageEncoder extends MessageToMessageEncoder<ResponseMessag
String timestamp = DateUtil.timestamp2string(); String timestamp = DateUtil.timestamp2string();
String encrtypt = MessageUtil.aesEncrypt(mpAccount.getId(), String encrtypt = MessageUtil.aesEncrypt(mpAccount.getId(),
mpAccount.getEncodingAesKey(), xmlContent); mpAccount.getEncodingAesKey(), xmlContent);
String msgSignature = MessageUtil.signature(mpAccount.getToken(), nonce, String msgSignature = MessageUtil.signature(mpAccount.getToken(),
timestamp, encrtypt); nonce, timestamp, encrtypt);
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = new HashMap<String, String>();
map.put("Encrypt", encrtypt); map.put("Encrypt", encrtypt);
map.put("MsgSignature", msgSignature); map.put("MsgSignature", msgSignature);
@ -60,12 +60,9 @@ public class WeixinMessageEncoder extends MessageToMessageEncoder<ResponseMessag
map.put("Nonce", nonce); map.put("Nonce", nonce);
String content = mapXstream.toXML(map); String content = mapXstream.toXML(map);
HttpResponse httpResponse = HttpUtil out.add(HttpUtil.createWeixinMessageResponse(content, null));
.createWeixinMessageResponse(content);
out.add(httpResponse);
log.info("\n=================aes encrtypt out================="); log.info("\n=================aes encrtypt out=================");
log.info("{}", map);
log.info("{}", content); log.info("{}", content);
} }
} }

View File

@ -4,23 +4,24 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpMethod; 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.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.HttpVersion;
import org.apache.http.entity.ContentType;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.mp.action.WeixinAction; import com.foxinmy.weixin4j.action.WeixinAction;
import com.foxinmy.weixin4j.mp.mapping.ActionMapping; import com.foxinmy.weixin4j.action.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.mp.util.HttpUtil; 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; import com.foxinmy.weixin4j.util.MessageUtil;
/** /**
* 微信被动消息处理类 * 微信被动消息处理类
*
* @className WeixinServerHandler * @className WeixinServerHandler
* @author jy * @author jy
* @date 2014年11月16日 * @date 2014年11月16日
@ -53,16 +54,15 @@ public class WeixinServerHandler extends
HttpWeixinMessage httpMessage) throws Exception { HttpWeixinMessage httpMessage) throws Exception {
log.info("\n=================message in=================\n{}", log.info("\n=================message in=================\n{}",
httpMessage); httpMessage);
boolean isGet = httpMessage.getMethod().equals(HttpMethod.GET.name());
boolean validate = false; boolean validate = false;
if (httpMessage.getMethod() == HttpMethod.GET if (isGet || httpMessage.getEncryptType() == EncryptType.RAW) {
|| httpMessage.getEncryptType() == EncryptType.RAW) {
validate = MessageUtil.signature(httpMessage.getToken(), validate = MessageUtil.signature(httpMessage.getToken(),
httpMessage.getTimeStamp(), httpMessage.getNonce()).equals( httpMessage.getTimeStamp(), httpMessage.getNonce()).equals(
httpMessage.getSignature()); httpMessage.getSignature());
if (httpMessage.getMethod() == HttpMethod.GET && validate) { if (isGet && validate) {
HttpResponse httpResponse = HttpUtil ctx.write(HttpUtil.createWeixinMessageResponse(
.createWeixinMessageResponse(httpMessage.getEchoStr()); httpMessage.getEchoStr(), ContentType.TEXT_PLAIN));
ctx.write(httpResponse);
return; return;
} }
} else { } else {
@ -88,15 +88,13 @@ public class WeixinServerHandler extends
log.info("\n=================message out=================\n{}", log.info("\n=================message out=================\n{}",
response); response);
if (response == null) { if (response == null) {
HttpResponse httpResponse = HttpUtil ctx.write(HttpUtil.createWeixinMessageResponse("",
.createWeixinMessageResponse(""); ContentType.TEXT_PLAIN));
ctx.write(httpResponse);
return; return;
} }
if (httpMessage.getEncryptType() == EncryptType.RAW) { if (httpMessage.getEncryptType() == EncryptType.RAW) {
HttpResponse httpResponse = HttpUtil ctx.write(HttpUtil.createWeixinMessageResponse(response.toXml(),
.createWeixinMessageResponse(response.toXml()); null));
ctx.write(httpResponse);
} else { } else {
ctx.write(response); ctx.write(response);
} }

View File

@ -6,15 +6,17 @@ import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.HttpServerCodec;
import com.foxinmy.weixin4j.mp.mapping.ActionMapping; import com.foxinmy.weixin4j.action.mapping.ActionMapping;
import com.foxinmy.weixin4j.mp.mapping.AnnotationActionMapping; import com.foxinmy.weixin4j.action.mapping.AnnotationActionMapping;
import com.foxinmy.weixin4j.mp.action.ImageAction;
public class WeixinServerInitializer extends ChannelInitializer<SocketChannel> { public class WeixinServerInitializer extends ChannelInitializer<SocketChannel> {
private final ActionMapping actionMapping; private final ActionMapping actionMapping;
public WeixinServerInitializer() { public WeixinServerInitializer() {
this.actionMapping = new AnnotationActionMapping(); this.actionMapping = new AnnotationActionMapping(
ImageAction.class.getPackage());
} }
@Override @Override

View File

@ -16,6 +16,7 @@ import io.netty.handler.codec.http.HttpResponse;
import java.util.Date; import java.util.Date;
import org.apache.http.Consts; import org.apache.http.Consts;
import org.apache.http.entity.ContentType;
/** /**
* HTTP工具类 * HTTP工具类
@ -28,7 +29,11 @@ import org.apache.http.Consts;
*/ */
public class HttpUtil { 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, FullHttpResponse httpResponse = new DefaultFullHttpResponse(HTTP_1_1,
OK, Unpooled.copiedBuffer(content, Consts.UTF_8)); OK, Unpooled.copiedBuffer(content, Consts.UTF_8));
httpResponse.headers().set(CONTENT_TYPE, httpResponse.headers().set(CONTENT_TYPE,

View File

@ -24,7 +24,7 @@ weixin4j-qy
+ `netty服务器` & `消息分发` + `netty服务器` & `消息分发`
+ 回调`AES`加密、解密 + 回调`AES`加密、解密
更新LOG 更新LOG
------- -------
@ -45,3 +45,7 @@ weixin4j-qy
+ **weixin4j-qy-api**: 新增`发送消息`接口 + **weixin4j-qy-api**: 新增`发送消息`接口
+ **weixin4j-qy-api**: 新增`菜单管理`接口 + **weixin4j-qy-api**: 新增`菜单管理`接口
* 2014-11-24
+ **weixin4j-qy-server**: 新增netty服务与消息分发

View File

@ -23,13 +23,15 @@ weixin.properties说明
| :---------- | :-------------- | | :---------- | :-------------- |
| account | 微信企业号信息 `json格式` | | account | 微信企业号信息 `json格式` |
| token_path | 使用FileTokenHolder时token保存的物理路径 | | token_path | 使用FileTokenHolder时token保存的物理路径 |
| media_path | 调用媒体接口时保存媒体文件的物理路径 |
示例(properties中换行用右斜杆\\) 示例(properties中换行用右斜杆\\)
> account={"id":"corpid","secret":"corpsecret", > account={"id":"corpid","secret":"corpsecret",
> "token":"开放者的token 非必须", > "token":"企业号中应用在回调模式下的token",
> "encodingAesKey":"AES加密密钥"} > "encodingAesKey":"企业号中应用在回调模式下AES加密密钥"}
> token_path=/tmp/weixin/token </br> > token_path=/tmp/weixin/token </br>
> media_path=/tmp/weixin/media </br>
2.实例化一个`WeixinProxy`对象,调用API 2.实例化一个`WeixinProxy`对象,调用API

View File

@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.qy;
import java.util.List; import java.util.List;
import com.alibaba.fastjson.JSONArray;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.model.WeixinQyAccount; import com.foxinmy.weixin4j.model.WeixinQyAccount;
@ -10,6 +9,7 @@ import com.foxinmy.weixin4j.qy.api.DepartApi;
import com.foxinmy.weixin4j.qy.api.TagApi; import com.foxinmy.weixin4j.qy.api.TagApi;
import com.foxinmy.weixin4j.qy.api.UserApi; import com.foxinmy.weixin4j.qy.api.UserApi;
import com.foxinmy.weixin4j.qy.model.Department; import com.foxinmy.weixin4j.qy.model.Department;
import com.foxinmy.weixin4j.qy.model.Tag;
import com.foxinmy.weixin4j.qy.model.User; import com.foxinmy.weixin4j.qy.model.User;
import com.foxinmy.weixin4j.qy.type.UserStatus; import com.foxinmy.weixin4j.qy.type.UserStatus;
import com.foxinmy.weixin4j.token.FileTokenHolder; import com.foxinmy.weixin4j.token.FileTokenHolder;
@ -251,13 +251,13 @@ public class WeixinProxy {
* @see <a href= * @see <a href=
* "http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E6.9B.B4.E6.96.B0.E6.A0.87.E7.AD.BE.E5.90.8D.E5.AD.97" * "http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E6.9B.B4.E6.96.B0.E6.A0.87.E7.AD.BE.E5.90.8D.E5.AD.97"
* >更新标签说明</a> * >更新标签说明</a>
* @see com.foxinmy.weixin4j.qy.model.Tag
* @see com.foxinmy.weixin4j.qy.api.TagApi * @see com.foxinmy.weixin4j.qy.api.TagApi
* @return 处理结果 * @return 处理结果
* @throws WeixinException * @throws WeixinException
*/ */
public JsonResult updateTag(int tagId, String tagName) public JsonResult updateTag(Tag tag) throws WeixinException {
throws WeixinException { return tagApi.updateTag(tag);
return tagApi.updateTag(tagId, tagName);
} }
/** /**
@ -280,11 +280,12 @@ public class WeixinProxy {
* *
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E8.8E.B7.E5.8F.96.E6.A0.87.E7.AD.BE.E5.88.97.E8.A1.A8">获取标签列表说明</a> * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E8.8E.B7.E5.8F.96.E6.A0.87.E7.AD.BE.E5.88.97.E8.A1.A8">获取标签列表说明</a>
* @see com.foxinmy.weixin4j.qy.model.Tag
* @see com.foxinmy.weixin4j.qy.api.TagApi * @see com.foxinmy.weixin4j.qy.api.TagApi
* @return 标签列表 * @return 标签列表
* @throws WeixinException * @throws WeixinException
*/ */
public JSONArray listTag() throws WeixinException { public List<Tag> listTag() throws WeixinException {
return tagApi.listTag(); return tagApi.listTag();
} }

View File

@ -3,12 +3,12 @@ package com.foxinmy.weixin4j.qy.api;
import java.util.List; import java.util.List;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.qy.model.Tag;
import com.foxinmy.weixin4j.qy.model.User; import com.foxinmy.weixin4j.qy.model.User;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
@ -59,15 +59,15 @@ public class TagApi extends BaseApi {
* "http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E6.9B.B4.E6.96.B0.E6.A0.87.E7.AD.BE.E5.90.8D.E5.AD.97" * "http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E6.9B.B4.E6.96.B0.E6.A0.87.E7.AD.BE.E5.90.8D.E5.AD.97"
* >更新标签说明</a> * >更新标签说明</a>
* @return 处理结果 * @return 处理结果
* @see com.foxinmy.weixin4j.qy.model.Tag
* @throws WeixinException * @throws WeixinException
*/ */
public JsonResult updateTag(int tagId, String tagName) public JsonResult updateTag(Tag tag) throws WeixinException {
throws WeixinException {
String tag_update_uri = getRequestUri("tag_update_uri"); String tag_update_uri = getRequestUri("tag_update_uri");
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
Response response = request.post(String.format(tag_update_uri, Response response = request.post(
token.getAccessToken()), String.format( String.format(tag_update_uri, token.getAccessToken()),
"{\"tagid\":%d,\"tagname\":\"%s\"}", tagId, tagName)); JSON.toJSONString(tag));
return response.getAsJsonResult(); return response.getAsJsonResult();
} }
@ -95,14 +95,16 @@ public class TagApi extends BaseApi {
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E8.8E.B7.E5.8F.96.E6.A0.87.E7.AD.BE.E5.88.97.E8.A1.A8">获取标签列表说明</a> * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E8.8E.B7.E5.8F.96.E6.A0.87.E7.AD.BE.E5.88.97.E8.A1.A8">获取标签列表说明</a>
* @return 标签列表 * @return 标签列表
* @see com.foxinmy.weixin4j.qy.model.Tag
* @throws WeixinException * @throws WeixinException
*/ */
public JSONArray listTag() throws WeixinException { public List<Tag> listTag() throws WeixinException {
String tag_list_uri = getRequestUri("tag_list_uri"); String tag_list_uri = getRequestUri("tag_list_uri");
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
Response response = request.post(String.format(tag_list_uri, Response response = request.post(String.format(tag_list_uri,
token.getAccessToken())); token.getAccessToken()));
return response.getAsJson().getJSONArray("taglist"); return JSON.parseArray(response.getAsJson().getString("taglist"),
Tag.class);
} }
/** /**

View File

@ -100,6 +100,29 @@ public class UserApi extends BaseApi {
return JSON.toJavaObject(obj, User.class); return JSON.toJavaObject(obj, User.class);
} }
/**
* code获取userid(管理员须拥有agent的使用权限agentid必须和跳转链接时所在的企业应用ID相同)
*
* @param code
* 通过员工授权获取到的code每次员工授权带上的code将不一样code只能使用一次5分钟未被使用自动过期
* @param agentid
* 跳转链接时所在的企业应用ID
* @return {"UserId":"员工UserID","DeviceId":"手机设备号(由微信在安装时随机生成)"}
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%BC%81%E4%B8%9A%E8%8E%B7%E5%8F%96code">企业获取code</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%A0%B9%E6%8D%AEcode%E8%8E%B7%E5%8F%96%E6%88%90%E5%91%98%E4%BF%A1%E6%81%AF">根据code获取成员信息</a>
* @throws WeixinException
*/
public JSONObject getUserid(String code, int agentid)
throws WeixinException {
String user_getid_uri = getRequestUri("user_getid_uri");
Token token = tokenHolder.getToken();
Response response = request.post(String.format(user_getid_uri,
token.getAccessToken(), code, agentid));
return response.getAsJson();
}
/** /**
* 获取部门成员 * 获取部门成员
* *
@ -156,4 +179,22 @@ public class UserApi extends BaseApi {
token.getAccessToken(), userid)); token.getAccessToken(), userid));
return response.getAsJsonResult(); return response.getAsJsonResult();
} }
/**
* 开启二次验证成功时调用(管理员须拥有userid对应员工的管理权限)
*
* @param userid
* 成员ID
* @return 调用结果
* @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">二次验证说明</a>
* @throws WeixinException
*/
public JsonResult authsucc(String userid) throws WeixinException {
String user_authsucc_uri = getRequestUri("user_authsucc_uri");
Token token = tokenHolder.getToken();
Response response = request.post(String.format(user_authsucc_uri,
token.getAccessToken(), userid));
return response.getAsJsonResult();
}
} }

View File

@ -15,14 +15,18 @@ department_list_uri={api_base_url}/department/list?access_token=%s
department_delete_uri={api_base_url}/department/delete?access_token=%s&id=%d department_delete_uri={api_base_url}/department/delete?access_token=%s&id=%d
# \u521b\u5efa\u6210\u5458 # \u521b\u5efa\u6210\u5458
user_create_uri={api_base_url}/user/create?access_token=%s user_create_uri={api_base_url}/user/create?access_token=%s
# \u66f4\u65b0\u6210\u5458 # \u66f4\u65b0\u6210\u5458\u4fe1\u606f
user_update_uri={api_base_url}/user/update?access_token=%s user_update_uri={api_base_url}/user/update?access_token=%s
# \u83b7\u53d6\u6210\u5458 # \u83b7\u53d6\u6210\u5458\u4fe1\u606f
user_get_uri={api_base_url}/user/get?access_token=%s&userid=%s user_get_uri={api_base_url}/user/get?access_token=%s&userid=%s
# code\u83b7\u53d6\u6210\u5458\u4fe1\u606f
user_getid_uri={api_base_url}/getuserinfo?access_token=%s&code=%s&agentid=%d
# \u83b7\u53d6\u90e8\u95e8\u6210\u5458 # \u83b7\u53d6\u90e8\u95e8\u6210\u5458
user_list_uri={api_base_url}/user/simplelist?access_token=%s&department_id=%d&fetch_child=%d&status=%d user_list_uri={api_base_url}/user/simplelist?access_token=%s&department_id=%d&fetch_child=%d&status=%d
# \u5220\u9664\u6210\u5458 # \u5220\u9664\u6210\u5458
user_delete_uri={api_base_url}/user/delete?access_token=%s&userid=%s user_delete_uri={api_base_url}/user/delete?access_token=%s&userid=%s
# \u6210\u5458\u4e8c\u6b21\u9a8c\u8bc1\u6210\u529f\u65f6\u8c03\u7528
user_authsucc_uri={api_base_url}/user/authsucc?access_token=%s&userid=%s
# \u521b\u5efa\u6807\u7b7e # \u521b\u5efa\u6807\u7b7e
tag_create_uri={api_base_url}/tag/create?access_token=%s tag_create_uri={api_base_url}/tag/create?access_token=%s
# \u66f4\u65b0\u6807\u7b7e # \u66f4\u65b0\u6807\u7b7e

View File

@ -0,0 +1,54 @@
package com.foxinmy.weixin4j.qy.model;
import java.io.Serializable;
import com.alibaba.fastjson.annotation.JSONField;
/**
* 标签对象
*
* @className Tag
* @author jy
* @date 2014年11月24日
* @since JDK 1.7
* @see
*/
public class Tag implements Serializable {
private static final long serialVersionUID = 5204620476267654921L;
@JSONField(name = "tagid")
private int id;
@JSONField(name = "tagname")
private String name;
public Tag() {
}
public Tag(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Tag [id=" + id + ", name=" + name + "]";
}
}

View File

@ -7,10 +7,10 @@ import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import com.alibaba.fastjson.JSONArray;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.qy.api.TagApi; import com.foxinmy.weixin4j.qy.api.TagApi;
import com.foxinmy.weixin4j.qy.model.Tag;
import com.foxinmy.weixin4j.qy.model.User; import com.foxinmy.weixin4j.qy.model.User;
/** /**
@ -38,7 +38,7 @@ public class TagTest extends TokenTest {
@Test @Test
public void update() throws WeixinException { public void update() throws WeixinException {
JsonResult result = tagApi.updateTag(1, "coder456"); JsonResult result = tagApi.updateTag(new Tag(1, "coder456"));
Assert.assertEquals("updated", result.getDesc()); Assert.assertEquals("updated", result.getDesc());
} }
@ -64,7 +64,7 @@ public class TagTest extends TokenTest {
@Test @Test
public void list() throws WeixinException { public void list() throws WeixinException {
JSONArray tags = tagApi.listTag(); List<Tag> tags = tagApi.listTag();
Assert.assertFalse(tags.isEmpty()); Assert.assertFalse(tags.isEmpty());
System.out.println(tags); System.out.println(tags);
} }

View File

@ -13,10 +13,34 @@ weixin4j-qy-server
如何使用 如何使用
-------- --------
1.正确填写`weixin.properties`中的属性值
| 属性名 | 说明 |
| :---------- | :-------------- |
| account | 微信企业号信息 `json格式` |
| token_path | 使用FileTokenHolder时token保存的物理路径 |
| media_path | 调用媒体接口时保存媒体文件的物理路径 |
示例(properties中换行用右斜杆\\)
> account={"id":"corpid","secret":"corpsecret",
> "token":"企业号中应用在回调模式下的token",
> "encodingAesKey":"企业号中应用在回调模式下AES加密密钥"}
> token_path=/tmp/weixin/token </br>
> media_path=/tmp/weixin/media </br>
2.mvn package,得到一个zip的压缩包,解压到启动目录(见`src/main/startup.sh/APP_HOME`)
3.启动netty服务(`com.foxinmy.weixin4j.mp.startup.WeixinQyServerBootstrap`)
sh startup.sh start
更新LOG 更新LOG
------- -------
* 2014-11-19 * 2014-11-19
+ 得到`weixin4j-qy-server`工程 + 得到`weixin4j-qy-server`工程
* 2014-11-24
+ 新增netty服务与消息分发

View File

@ -0,0 +1,20 @@
package com.foxinmy.weixin4j.qy.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;
/**
* 图片消息处理
*
* @className ImageAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.ImageMessage
*/
@ActionAnnotation(msgType = MessageType.image)
public class ImageAction extends DebugAction<ImageMessage> {
}

View File

@ -0,0 +1,20 @@
package com.foxinmy.weixin4j.qy.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;
/**
* 链接消息处理
*
* @className LinkAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.LinkMessage
*/
@ActionAnnotation(msgType = MessageType.link)
public class LinkAction extends DebugAction<LinkMessage> {
}

View File

@ -0,0 +1,20 @@
package com.foxinmy.weixin4j.qy.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;
/**
* 地理位置处理
*
* @className LocationAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.LocationMessage
*/
@ActionAnnotation(msgType = MessageType.location)
public class LocationAction extends DebugAction<LocationMessage> {
}

View File

@ -0,0 +1 @@
普通消息对应的Action

View File

@ -0,0 +1,26 @@
package com.foxinmy.weixin4j.qy.action;
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;
/**
* 文字消息处理
*
* @className TextAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.TextMessage
*/
@ActionAnnotation(msgType = MessageType.text)
public class TextAction extends AbstractAction<TextMessage> {
@Override
public ResponseMessage execute(TextMessage inMessage) {
return new ResponseMessage(new Text("Hello World!"), inMessage);
}
}

View File

@ -0,0 +1,20 @@
package com.foxinmy.weixin4j.qy.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;
/**
* 视频消息处理
*
* @className VideoAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.VideoMessage
*/
@ActionAnnotation(msgType = MessageType.video)
public class VideoAction extends DebugAction<VideoMessage> {
}

View File

@ -0,0 +1,20 @@
package com.foxinmy.weixin4j.qy.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;
/**
* 语音消息处理
*
* @className VoiceAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.VoiceMessage
*/
@ActionAnnotation(msgType = MessageType.voice)
public class VoiceAction extends DebugAction<VoiceMessage> {
}

View File

@ -0,0 +1,21 @@
package com.foxinmy.weixin4j.qy.action.event;
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;
/**
* 上报地理位置后触发
*
* @className LocationAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.LocationEventMessage
*/
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.location })
public class LocationAction extends DebugAction<LocationEventMessage> {
}

View File

@ -0,0 +1,21 @@
package com.foxinmy.weixin4j.qy.action.event;
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;
/**
* 群发消息发送动作完成后触发
*
* @className MassSendAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.MassEventMessage
*/
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.massendjobfinish })
public class MassSendAction extends DebugAction<MassEventMessage> {
}

View File

@ -0,0 +1,21 @@
package com.foxinmy.weixin4j.qy.action.event;
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;
/**
* click类型菜单点击时触发
*
* @className MenuClickAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage
*/
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.click })
public class MenuClickAction extends DebugAction<MenuEventMessage> {
}

View File

@ -0,0 +1,21 @@
package com.foxinmy.weixin4j.qy.action.event;
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;
/**
* 点击菜单发送地理位置时触发
*
* @className MenuLocationAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuLocationEventMessage
*/
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.location_select })
public class MenuLocationAction extends DebugAction<MenuLocationEventMessage> {
}

View File

@ -0,0 +1,23 @@
package com.foxinmy.weixin4j.qy.action.event;
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;
/**
* 点击菜单发送图片时触发
*
* @className MenuPhotoAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage
*/
@ActionAnnotation(msgType = MessageType.event, eventType = {
EventType.pic_photo_or_album, EventType.pic_sysphoto,
EventType.pic_weixin })
public class MenuPhotoAction extends DebugAction<MenuPhotoEventMessage> {
}

View File

@ -0,0 +1,22 @@
package com.foxinmy.weixin4j.qy.action.event;
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;
/**
* 点击菜单扫描时触发
*
* @className MenuScanAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage
*/
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.scancode_push,
EventType.scancode_waitmsg })
public class MenuScanAction extends DebugAction<MenuScanEventMessage> {
}

View File

@ -0,0 +1,21 @@
package com.foxinmy.weixin4j.qy.action.event;
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;
/**
* view类型菜单点击时触发
*
* @className MenuViewAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage
*/
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.view })
public class MenuViewAction extends DebugAction<MenuEventMessage> {
}

View File

@ -0,0 +1 @@
事件消息对应的Action

View File

@ -0,0 +1,21 @@
package com.foxinmy.weixin4j.qy.action.event;
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;
/**
* 扫描事件时触发
*
* @className ScanAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.ScanEventMessage
*/
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.scan })
public class ScanAction extends DebugAction<ScanEventMessage> {
}

View File

@ -0,0 +1,21 @@
package com.foxinmy.weixin4j.qy.action.event;
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;
/**
* 关注时触发
*
* @className SubscribeAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.ScribeEventMessage
*/
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.subscribe })
public class SubscribeAction extends DebugAction<ScribeEventMessage> {
}

View File

@ -0,0 +1,22 @@
package com.foxinmy.weixin4j.qy.action.event;
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;
/**
* 模板消息发送动作完成时触发
*
* @className TemplateSendAction
* @author jy
* @date 2014年10月10日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage
*/
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.templatesendjobfinish })
public class TemplateSendAction extends
DebugAction<TemplatesendjobfinishMessage> {
}

View File

@ -0,0 +1,21 @@
package com.foxinmy.weixin4j.qy.action.event;
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;
/**
* 取消关注时触发
*
* @className UnsubscribeAction
* @author jy
* @date 2014年10月10日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.ScribeEventMessage
*/
@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.unsubscribe })
public class UnsubscribeAction extends DebugAction<ScribeEventMessage> {
}

View File

@ -0,0 +1,5 @@
WeixinMessageDecoder:对微信消息进行解码
WeixinMessageEncoder:对微信消息进行编码
WeixinServerHandler:微信请求处理类

View File

@ -0,0 +1,77 @@
package com.foxinmy.weixin4j.qy.server;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.QueryStringDecoder;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.model.WeixinQyAccount;
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;
/**
* 微信消息解码类
*
* @className WeixinMessageDecoder
* @author jy
* @date 2014年11月13日
* @since JDK 1.7
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%9B%9E%E8%B0%83%E6%A8%A1%E5%BC%8F">回调模式</a>
*/
public class WeixinMessageDecoder extends
MessageToMessageDecoder<FullHttpRequest> {
private final Logger log = LoggerFactory.getLogger(getClass());
@Override
protected void decode(ChannelHandlerContext ctx, FullHttpRequest req,
List<Object> out) throws Exception {
WeixinQyAccount qyAccount = ConfigUtil.getWeixinQyAccount();
String xmlContent = req.content().toString(Consts.UTF_8);
HttpWeixinMessage message = new HttpWeixinMessage();
message.setXmlContent(xmlContent);
if (StringUtils.isNotBlank(xmlContent)) {
message = XStream.get(xmlContent, HttpWeixinMessage.class);
message.setXmlContent(MessageUtil.aesDecrypt(qyAccount.getId(),
qyAccount.getEncodingAesKey(), message.getEncryptContent()));
}
message.setMethod(req.getMethod().name());
QueryStringDecoder queryDecoder = new QueryStringDecoder(req.getUri(),
true);
log.info("\n=================receive request=================");
log.info("{}", req.getMethod());
log.info("{}", req.getUri());
log.info("{}", xmlContent);
Map<String, List<String>> parameters = queryDecoder.parameters();
String msgSignature = parameters.containsKey("msg_signature") ? parameters
.get("msg_signature").get(0) : "";
message.setMsgSignature(msgSignature);
String echoStr = parameters.containsKey("echostr") ? parameters.get(
"echostr").get(0) : "";
message.setEchoStr(echoStr);
String timeStamp = parameters.containsKey("timestamp") ? parameters
.get("timestamp").get(0) : "";
message.setTimeStamp(timeStamp);
String nonce = parameters.containsKey("nonce") ? parameters
.get("nonce").get(0) : "";
message.setNonce(nonce);
String signature = parameters.containsKey("signature") ? parameters
.get("signature").get(0) : "";
message.setSignature(signature);
message.setToken(qyAccount.getToken());
message.setEncryptType(EncryptType.AES);
out.add(message);
}
}

View File

@ -0,0 +1,69 @@
package com.foxinmy.weixin4j.qy.server;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.model.WeixinQyAccount;
import com.foxinmy.weixin4j.qy.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;
import com.foxinmy.weixin4j.util.RandomUtil;
import com.foxinmy.weixin4j.xml.Map2ObjectConverter;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.core.ClassLoaderReference;
import com.thoughtworks.xstream.mapper.DefaultMapper;
/**
* 微信消息编码类
*
* @className WeixinMessageEncoder
* @author jy
* @date 2014年11月13日
* @since JDK 1.7
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%8A%A0%E8%A7%A3%E5%AF%86%E6%96%B9%E6%A1%88%E7%9A%84%E8%AF%A6%E7%BB%86%E8%AF%B4%E6%98%8E">加密接入指引</a>
*/
public class WeixinMessageEncoder extends
MessageToMessageEncoder<ResponseMessage> {
private final Logger log = LoggerFactory.getLogger(getClass());
protected final static XStream mapXstream = XStream.get();
static {
mapXstream.alias("xml", Map.class);
mapXstream.registerConverter(new Map2ObjectConverter(new DefaultMapper(
new ClassLoaderReference(XStream.class.getClassLoader()))));
}
@Override
protected void encode(ChannelHandlerContext ctx, ResponseMessage response,
List<Object> out) throws Exception {
WeixinQyAccount qyAccount = ConfigUtil.getWeixinQyAccount();
String xmlContent = response.toXml();
String nonce = RandomUtil.generateString(32);
String timestamp = DateUtil.timestamp2string();
String encrtypt = MessageUtil.aesEncrypt(qyAccount.getId(),
qyAccount.getEncodingAesKey(), xmlContent);
String msgSignature = MessageUtil.signature(qyAccount.getToken(),
nonce, timestamp, encrtypt);
Map<String, String> map = new HashMap<String, String>();
map.put("Encrypt", encrtypt);
map.put("MsgSignature", msgSignature);
map.put("TimeStamp", timestamp);
map.put("Nonce", nonce);
String content = mapXstream.toXML(map);
out.add(HttpUtil.createWeixinMessageResponse(
content, null));
log.info("\n=================aes encrtypt out=================");
log.info("{}", content);
}
}

View File

@ -0,0 +1,96 @@
package com.foxinmy.weixin4j.qy.server;
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.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.action.WeixinAction;
import com.foxinmy.weixin4j.action.mapping.ActionMapping;
import com.foxinmy.weixin4j.qy.util.HttpUtil;
import com.foxinmy.weixin4j.response.HttpWeixinMessage;
import com.foxinmy.weixin4j.response.ResponseMessage;
import com.foxinmy.weixin4j.util.MessageUtil;
/**
* 微信被动消息处理类
*
* @className WeixinServerHandler
* @author jy
* @date 2014年11月16日
* @since JDK 1.7
* @see
*/
public class WeixinServerHandler extends
SimpleChannelInboundHandler<HttpWeixinMessage> {
private final Logger log = LoggerFactory.getLogger(getClass());
private final ActionMapping actionMapping;
public WeixinServerHandler(ActionMapping actionMapping) {
this.actionMapping = actionMapping;
}
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx,
HttpWeixinMessage httpMessage) throws Exception {
log.info("\n=================message in=================\n{}",
httpMessage);
boolean isGet = httpMessage.getMethod().equals(HttpMethod.GET.name());
boolean validate = false;
if (isGet) {
validate = MessageUtil.signature(httpMessage.getToken(),
httpMessage.getTimeStamp(), httpMessage.getNonce()).equals(
httpMessage.getSignature());
if (validate) {
ctx.write(HttpUtil.createWeixinMessageResponse(
httpMessage.getEchoStr(), ContentType.TEXT_PLAIN));
return;
}
} else {
validate = MessageUtil.signature(httpMessage.getToken(),
httpMessage.getTimeStamp(), httpMessage.getNonce(),
httpMessage.getEncryptContent()).equals(
httpMessage.getMsgSignature());
}
if (!validate) {
ctx.write(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.FORBIDDEN));
return;
}
String xmlContent = httpMessage.getXmlContent();
WeixinAction action = actionMapping.getAction(xmlContent);
if (action == null) {
ctx.write(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.NOT_FOUND));
return;
}
ResponseMessage response = action.execute(xmlContent);
log.info("\n=================message out=================\n{}",
response);
if (response == null) {
ctx.write(HttpUtil.createWeixinMessageResponse("",
ContentType.TEXT_PLAIN));
return;
}
ctx.write(response);
}
}

View File

@ -0,0 +1,30 @@
package com.foxinmy.weixin4j.qy.server;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import com.foxinmy.weixin4j.action.mapping.ActionMapping;
import com.foxinmy.weixin4j.action.mapping.AnnotationActionMapping;
import com.foxinmy.weixin4j.qy.action.ImageAction;
public class WeixinServerInitializer extends ChannelInitializer<SocketChannel> {
private final ActionMapping actionMapping;
public WeixinServerInitializer() {
this.actionMapping = new AnnotationActionMapping(
ImageAction.class.getPackage());
}
@Override
protected void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new WeixinMessageDecoder());
pipeline.addLast(new WeixinMessageEncoder());
pipeline.addLast(new WeixinServerHandler(actionMapping));
}
}

View File

@ -0,0 +1,54 @@
package com.foxinmy.weixin4j.qy.startup;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import java.util.ResourceBundle;
import com.foxinmy.weixin4j.qy.server.WeixinServerInitializer;
/**
* 微信服务netty启动程序
*
* @className WeixinServerBootstrap
* @author jy
* @date 2014年10月12日
* @since JDK 1.7
* @see
*/
public final class WeixinQyServerBootstrap {
private final static int port;
private final static int workerThreads;
static {
ResourceBundle netty = ResourceBundle.getBundle("netty");
port = Integer.parseInt(netty.getString("port"));
workerThreads = Integer.parseInt(netty.getString("workerThreads"));
}
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(workerThreads);
try {
ServerBootstrap b = new ServerBootstrap();
b.option(ChannelOption.SO_BACKLOG, 1024);
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler())
.childHandler(new WeixinServerInitializer());
Channel ch = b.bind(port).sync().channel();
System.err.println("weixin server startup OK:" + port);
ch.closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}

View File

@ -0,0 +1,50 @@
package com.foxinmy.weixin4j.qy.util;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpHeaders.Names.DATE;
import static io.netty.handler.codec.http.HttpHeaders.Names.SERVER;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.handler.codec.http.HttpResponse;
import java.util.Date;
import org.apache.http.Consts;
import org.apache.http.entity.ContentType;
/**
* HTTP工具类
*
* @className HttpUtil
* @author jy
* @date 2014年11月15日
* @since JDK 1.7
* @see
*/
public class HttpUtil {
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,
String.format("%s;encoding=%s", contentType.getMimeType(),
Consts.UTF_8.displayName()));
httpResponse.headers().set(CONTENT_LENGTH, content.getBytes().length);
httpResponse.headers().set(CONNECTION, Values.KEEP_ALIVE);
httpResponse.headers().set(DATE, new Date());
httpResponse.headers().set(SERVER, "netty4");
return httpResponse;
}
}

Some files were not shown because too many files have changed in this diff Show More