@@ -3,6 +3,7 @@ package chanjarster.weixin.api; | |||||
import java.util.Map; | import java.util.Map; | ||||
import chanjarster.weixin.bean.WxXmlMessage; | import chanjarster.weixin.bean.WxXmlMessage; | ||||
import chanjarster.weixin.bean.WxXmlOutMessage; | |||||
/** | /** | ||||
* 处理微信推送消息的处理器接口 | * 处理微信推送消息的处理器接口 | ||||
@@ -17,6 +18,6 @@ public interface WxMessageHandler { | |||||
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 | * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 | ||||
* @return xml格式的消息,如果在异步规则里处理的话,可以返回null | * @return xml格式的消息,如果在异步规则里处理的话,可以返回null | ||||
*/ | */ | ||||
public WxXmlMessage handle(WxXmlMessage wxMessage, Map<String, Object> context); | |||||
public WxXmlOutMessage handle(WxXmlMessage wxMessage, Map<String, Object> context); | |||||
} | } |
@@ -8,6 +8,7 @@ import java.util.concurrent.ExecutorService; | |||||
import java.util.concurrent.Executors; | import java.util.concurrent.Executors; | ||||
import chanjarster.weixin.bean.WxXmlMessage; | import chanjarster.weixin.bean.WxXmlMessage; | ||||
import chanjarster.weixin.bean.WxXmlOutMessage; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
@@ -55,7 +56,7 @@ public class WxMessageRouter { | |||||
* 处理微信消息 | * 处理微信消息 | ||||
* @param wxMessage | * @param wxMessage | ||||
*/ | */ | ||||
public WxXmlMessage route(final WxXmlMessage wxMessage) { | |||||
public WxXmlOutMessage route(final WxXmlMessage wxMessage) { | |||||
final List<Rule> matchRules = new ArrayList<Rule>(); | final List<Rule> matchRules = new ArrayList<Rule>(); | ||||
// 收集匹配的规则 | // 收集匹配的规则 | ||||
for (final Rule rule : rules) { | for (final Rule rule : rules) { | ||||
@@ -84,7 +85,7 @@ public class WxMessageRouter { | |||||
return null; | return null; | ||||
} | } | ||||
WxXmlMessage res = null; | |||||
WxXmlOutMessage res = null; | |||||
for (final Rule rule : matchRules) { | for (final Rule rule : matchRules) { | ||||
// 返回最后一个匹配规则的结果 | // 返回最后一个匹配规则的结果 | ||||
res = rule.service(wxMessage); | res = rule.service(wxMessage); | ||||
@@ -254,7 +255,7 @@ public class WxMessageRouter { | |||||
* @param wxMessage | * @param wxMessage | ||||
* @return true 代表继续执行别的router,false 代表停止执行别的router | * @return true 代表继续执行别的router,false 代表停止执行别的router | ||||
*/ | */ | ||||
protected WxXmlMessage service(WxXmlMessage wxMessage) { | |||||
protected WxXmlOutMessage service(WxXmlMessage wxMessage) { | |||||
Map<String, Object> context = new HashMap<String, Object>(); | Map<String, Object> context = new HashMap<String, Object>(); | ||||
// 如果拦截器不通过 | // 如果拦截器不通过 | ||||
for (WxMessageInterceptor interceptor : this.interceptors) { | for (WxMessageInterceptor interceptor : this.interceptors) { | ||||
@@ -264,7 +265,7 @@ public class WxMessageRouter { | |||||
} | } | ||||
// 交给handler处理 | // 交给handler处理 | ||||
WxXmlMessage res = null; | |||||
WxXmlOutMessage res = null; | |||||
for (WxMessageHandler handler : this.handlers) { | for (WxMessageHandler handler : this.handlers) { | ||||
// 返回最后handler的结果 | // 返回最后handler的结果 | ||||
res = handler.handle(wxMessage, context); | res = handler.handle(wxMessage, context); | ||||
@@ -132,19 +132,19 @@ public class WxXmlMessage { | |||||
/** | /** | ||||
* group_id下粉丝数;或者openid_list中的粉丝数 | * group_id下粉丝数;或者openid_list中的粉丝数 | ||||
*/ | */ | ||||
private int TotalCount; | |||||
private Integer TotalCount; | |||||
/** | /** | ||||
* 过滤(过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超4条的过滤)后,准备发送的粉丝数,原则上,FilterCount = SentCount + ErrorCount | * 过滤(过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超4条的过滤)后,准备发送的粉丝数,原则上,FilterCount = SentCount + ErrorCount | ||||
*/ | */ | ||||
private int FilterCount; | |||||
private Integer FilterCount; | |||||
/** | /** | ||||
* 发送成功的粉丝数 | * 发送成功的粉丝数 | ||||
*/ | */ | ||||
private int SentCount; | |||||
private Integer SentCount; | |||||
/** | /** | ||||
* 发送失败的粉丝数 | * 发送失败的粉丝数 | ||||
*/ | */ | ||||
private int ErrorCount; | |||||
private Integer ErrorCount; | |||||
public String getToUserName() { | public String getToUserName() { | ||||
return ToUserName; | return ToUserName; | ||||
@@ -340,14 +340,6 @@ public class WxXmlMessage { | |||||
FromUserName = fromUserName; | FromUserName = fromUserName; | ||||
} | } | ||||
public String toXml() { | |||||
try { | |||||
return XmlTransformer.toXml(WxXmlMessage.class, this); | |||||
} catch (JAXBException e) { | |||||
throw new RuntimeException(e); | |||||
} | |||||
} | |||||
public static WxXmlMessage fromXml(String xml) { | public static WxXmlMessage fromXml(String xml) { | ||||
try { | try { | ||||
return XmlTransformer.fromXml(WxXmlMessage.class, xml); | return XmlTransformer.fromXml(WxXmlMessage.class, xml); | ||||
@@ -370,28 +362,28 @@ public class WxXmlMessage { | |||||
public void setStatus(String status) { | public void setStatus(String status) { | ||||
Status = status; | Status = status; | ||||
} | } | ||||
public int getTotalCount() { | |||||
public Integer getTotalCount() { | |||||
return TotalCount; | return TotalCount; | ||||
} | } | ||||
public void setTotalCount(int totalCount) { | |||||
public void setTotalCount(Integer totalCount) { | |||||
TotalCount = totalCount; | TotalCount = totalCount; | ||||
} | } | ||||
public int getFilterCount() { | |||||
public Integer getFilterCount() { | |||||
return FilterCount; | return FilterCount; | ||||
} | } | ||||
public void setFilterCount(int filterCount) { | |||||
public void setFilterCount(Integer filterCount) { | |||||
FilterCount = filterCount; | FilterCount = filterCount; | ||||
} | } | ||||
public int getSentCount() { | |||||
public Integer getSentCount() { | |||||
return SentCount; | return SentCount; | ||||
} | } | ||||
public void setSentCount(int sentCount) { | |||||
public void setSentCount(Integer sentCount) { | |||||
SentCount = sentCount; | SentCount = sentCount; | ||||
} | } | ||||
public int getErrorCount() { | |||||
public Integer getErrorCount() { | |||||
return ErrorCount; | return ErrorCount; | ||||
} | } | ||||
public void setErrorCount(int errorCount) { | |||||
public void setErrorCount(Integer errorCount) { | |||||
ErrorCount = errorCount; | ErrorCount = errorCount; | ||||
} | } | ||||
@Override | @Override | ||||
@@ -0,0 +1,32 @@ | |||||
package chanjarster.weixin.bean; | |||||
import javax.xml.bind.annotation.XmlAccessType; | |||||
import javax.xml.bind.annotation.XmlAccessorType; | |||||
import javax.xml.bind.annotation.XmlElement; | |||||
import javax.xml.bind.annotation.XmlRootElement; | |||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; | |||||
import chanjarster.weixin.api.WxConsts; | |||||
import chanjarster.weixin.util.xml.MediaIdMarshaller; | |||||
@XmlRootElement(name = "xml") | |||||
@XmlAccessorType(XmlAccessType.FIELD) | |||||
public class WxXmlOutImageMessage extends WxXmlOutMessage { | |||||
@XmlElement(name="Image") | |||||
@XmlJavaTypeAdapter(MediaIdMarshaller.class) | |||||
private String MediaId; | |||||
public WxXmlOutImageMessage() { | |||||
this.MsgType = WxConsts.XML_MSG_IMAGE; | |||||
} | |||||
public String getMediaId() { | |||||
return MediaId; | |||||
} | |||||
public void setMediaId(String mediaId) { | |||||
MediaId = mediaId; | |||||
} | |||||
} |
@@ -0,0 +1,72 @@ | |||||
package chanjarster.weixin.bean; | |||||
import javax.xml.bind.JAXBException; | |||||
import javax.xml.bind.annotation.XmlAccessType; | |||||
import javax.xml.bind.annotation.XmlAccessorType; | |||||
import javax.xml.bind.annotation.XmlElement; | |||||
import javax.xml.bind.annotation.XmlRootElement; | |||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; | |||||
import chanjarster.weixin.util.xml.AdapterCDATA; | |||||
import chanjarster.weixin.util.xml.XmlTransformer; | |||||
@XmlRootElement(name = "xml") | |||||
@XmlAccessorType(XmlAccessType.FIELD) | |||||
public class WxXmlOutMessage { | |||||
@XmlElement(name="ToUserName") | |||||
@XmlJavaTypeAdapter(AdapterCDATA.class) | |||||
protected String ToUserName; | |||||
@XmlElement(name="FromUserName") | |||||
@XmlJavaTypeAdapter(AdapterCDATA.class) | |||||
protected String FromUserName; | |||||
@XmlElement(name="CreateTime") | |||||
protected Long CreateTime; | |||||
@XmlElement(name="MsgType") | |||||
@XmlJavaTypeAdapter(AdapterCDATA.class) | |||||
protected String MsgType; | |||||
public String getToUserName() { | |||||
return ToUserName; | |||||
} | |||||
public void setToUserName(String toUserName) { | |||||
ToUserName = toUserName; | |||||
} | |||||
public String getFromUserName() { | |||||
return FromUserName; | |||||
} | |||||
public void setFromUserName(String fromUserName) { | |||||
FromUserName = fromUserName; | |||||
} | |||||
public Long getCreateTime() { | |||||
return CreateTime; | |||||
} | |||||
public void setCreateTime(Long createTime) { | |||||
CreateTime = createTime; | |||||
} | |||||
public String getMsgType() { | |||||
return MsgType; | |||||
} | |||||
public void setMsgType(String msgType) { | |||||
MsgType = msgType; | |||||
} | |||||
public String toXml() { | |||||
try { | |||||
return XmlTransformer.toXml((Class)this.getClass(), this); | |||||
} catch (JAXBException e) { | |||||
} | |||||
return null; | |||||
} | |||||
} |
@@ -0,0 +1,33 @@ | |||||
package chanjarster.weixin.bean; | |||||
import javax.xml.bind.annotation.XmlAccessType; | |||||
import javax.xml.bind.annotation.XmlAccessorType; | |||||
import javax.xml.bind.annotation.XmlElement; | |||||
import javax.xml.bind.annotation.XmlRootElement; | |||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; | |||||
import chanjarster.weixin.api.WxConsts; | |||||
import chanjarster.weixin.util.xml.AdapterCDATA; | |||||
@XmlRootElement(name = "xml") | |||||
@XmlAccessorType(XmlAccessType.FIELD) | |||||
public class WxXmlOutTextMessage extends WxXmlOutMessage { | |||||
@XmlElement(name="Content") | |||||
@XmlJavaTypeAdapter(AdapterCDATA.class) | |||||
private String Content; | |||||
public WxXmlOutTextMessage() { | |||||
this.MsgType = WxConsts.XML_MSG_TEXT; | |||||
} | |||||
public String getContent() { | |||||
return Content; | |||||
} | |||||
public void setContent(String content) { | |||||
Content = content; | |||||
} | |||||
} |
@@ -0,0 +1,27 @@ | |||||
package chanjarster.weixin.bean; | |||||
import javax.xml.bind.annotation.XmlAccessType; | |||||
import javax.xml.bind.annotation.XmlAccessorType; | |||||
import javax.xml.bind.annotation.XmlElement; | |||||
import javax.xml.bind.annotation.XmlRootElement; | |||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; | |||||
import chanjarster.weixin.util.xml.MediaIdMarshaller; | |||||
@XmlRootElement(name = "xml") | |||||
@XmlAccessorType(XmlAccessType.FIELD) | |||||
public class WxXmlOutVoiceMessage extends WxXmlOutMessage { | |||||
@XmlElement(name="Voice") | |||||
@XmlJavaTypeAdapter(MediaIdMarshaller.class) | |||||
private String MediaId; | |||||
public String getMediaId() { | |||||
return MediaId; | |||||
} | |||||
public void setMediaId(String mediaId) { | |||||
MediaId = mediaId; | |||||
} | |||||
} |
@@ -0,0 +1,21 @@ | |||||
package chanjarster.weixin.util.xml; | |||||
import javax.xml.bind.annotation.adapters.XmlAdapter; | |||||
/** | |||||
* @author chanjarster | |||||
*/ | |||||
public class MediaIdMarshaller extends XmlAdapter<String, String> { | |||||
@Override | |||||
public String marshal(String arg0) throws Exception { | |||||
return "<MediaId><![CDATA[" + arg0 + "]]></MediaId>"; | |||||
} | |||||
@Override | |||||
public String unmarshal(String arg0) throws Exception { | |||||
// do nothing | |||||
return arg0; | |||||
} | |||||
} |
@@ -7,6 +7,7 @@ import org.testng.annotations.DataProvider; | |||||
import org.testng.annotations.Test; | import org.testng.annotations.Test; | ||||
import chanjarster.weixin.bean.WxXmlMessage; | import chanjarster.weixin.bean.WxXmlMessage; | ||||
import chanjarster.weixin.bean.WxXmlOutMessage; | |||||
/** | /** | ||||
* 测试消息路由器 | * 测试消息路由器 | ||||
@@ -65,7 +66,7 @@ public class WxMessageRouterTest { | |||||
final WxMessageRouter router = new WxMessageRouter(); | final WxMessageRouter router = new WxMessageRouter(); | ||||
router.rule().handler(new WxMessageHandler() { | router.rule().handler(new WxMessageHandler() { | ||||
@Override | @Override | ||||
public WxXmlMessage handle(WxXmlMessage wxMessage, Map<String, Object> context) { | |||||
public WxXmlOutMessage handle(WxXmlMessage wxMessage, Map<String, Object> context) { | |||||
// TODO Auto-generated method stub | // TODO Auto-generated method stub | ||||
return null; | return null; | ||||
} | } | ||||
@@ -144,7 +145,7 @@ public class WxMessageRouterTest { | |||||
} | } | ||||
@Override | @Override | ||||
public WxXmlMessage handle(WxXmlMessage wxMessage, Map<String, Object> context) { | |||||
public WxXmlOutMessage handle(WxXmlMessage wxMessage, Map<String, Object> context) { | |||||
sb.append(this.echoStr).append(','); | sb.append(this.echoStr).append(','); | ||||
return null; | return null; | ||||
} | } | ||||
@@ -61,33 +61,4 @@ public class WxXmlMessageTest { | |||||
Assert.assertEquals(wxMessage.getPrecision(), new Double(119.385040)); | Assert.assertEquals(wxMessage.getPrecision(), new Double(119.385040)); | ||||
} | } | ||||
public void testToXml() { | |||||
WxXmlMessage wxMessage = new WxXmlMessage(); | |||||
wxMessage.setToUserName("toUser"); | |||||
wxMessage.setFromUserName("fromUser"); | |||||
wxMessage.setCreateTime(new Long(1348831860l)); | |||||
wxMessage.setMsgType(WxConsts.XML_MSG_TEXT); | |||||
wxMessage.setContent("this is a test"); | |||||
wxMessage.setMsgId(new Long(1234567890123456l)); | |||||
wxMessage.setPicUrl("this is a url"); | |||||
wxMessage.setMediaId("media_id"); | |||||
wxMessage.setFormat("Format"); | |||||
wxMessage.setThumbMediaId("thumb_media_id"); | |||||
wxMessage.setLocation_X(new Double(23.134521d)); | |||||
wxMessage.setLocation_Y(new Double(113.358803d)); | |||||
wxMessage.setScale(new Double(20)); | |||||
wxMessage.setLabel("位置信息"); | |||||
wxMessage.setDescription("公众平台官网链接"); | |||||
wxMessage.setUrl("url"); | |||||
wxMessage.setTitle("公众平台官网链接"); | |||||
wxMessage.setEvent("subscribe"); | |||||
wxMessage.setEventKey("qrscene_123123"); | |||||
wxMessage.setTicket("TICKET"); | |||||
wxMessage.setLatitude(new Double(23.137466)); | |||||
wxMessage.setLongitude(new Double(113.352425)); | |||||
wxMessage.setPrecision(new Double(119.385040)); | |||||
String xml = wxMessage.toXml(); | |||||
Assert.assertEquals(wxMessage, WxXmlMessage.fromXml(xml)); | |||||
} | |||||
} | } |
@@ -0,0 +1,28 @@ | |||||
package chanjarster.weixin.bean; | |||||
import org.testng.Assert; | |||||
import org.testng.annotations.Test; | |||||
@Test | |||||
public class WxXmlOutImageMessageTest { | |||||
public void test() { | |||||
WxXmlOutImageMessage m = new WxXmlOutImageMessage(); | |||||
m.setMediaId("ddfefesfsdfef"); | |||||
m.setCreateTime(1122l); | |||||
m.setFromUserName("from"); | |||||
m.setToUserName("to"); | |||||
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" | |||||
+ "<xml>" | |||||
+ "<ToUserName><![CDATA[to]]></ToUserName>" | |||||
+ "<FromUserName><![CDATA[from]]></FromUserName>" | |||||
+ "<CreateTime>1122</CreateTime>" | |||||
+ "<MsgType><![CDATA[image]]></MsgType>" | |||||
+ "<Image><MediaId><![CDATA[ddfefesfsdfef]]></MediaId></Image>" | |||||
+ "</xml>"; | |||||
System.out.println(m.toXml()); | |||||
Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); | |||||
} | |||||
} |
@@ -0,0 +1,28 @@ | |||||
package chanjarster.weixin.bean; | |||||
import org.testng.Assert; | |||||
import org.testng.annotations.Test; | |||||
@Test | |||||
public class WxXmlOutTextMessageTest { | |||||
public void test() { | |||||
WxXmlOutTextMessage m = new WxXmlOutTextMessage(); | |||||
m.setContent("content"); | |||||
m.setCreateTime(1122l); | |||||
m.setFromUserName("from"); | |||||
m.setToUserName("to"); | |||||
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" | |||||
+ "<xml>" | |||||
+ "<ToUserName><![CDATA[to]]></ToUserName>" | |||||
+ "<FromUserName><![CDATA[from]]></FromUserName>" | |||||
+ "<CreateTime>1122</CreateTime>" | |||||
+ "<MsgType><![CDATA[text]]></MsgType>" | |||||
+ "<Content><![CDATA[content]]></Content>" | |||||
+ "</xml>"; | |||||
System.out.println(m.toXml()); | |||||
Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); | |||||
} | |||||
} |