@@ -3,6 +3,7 @@ package chanjarster.weixin.api; | |||
import java.util.Map; | |||
import chanjarster.weixin.bean.WxXmlMessage; | |||
import chanjarster.weixin.bean.WxXmlOutMessage; | |||
/** | |||
* 处理微信推送消息的处理器接口 | |||
@@ -17,6 +18,6 @@ public interface WxMessageHandler { | |||
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 | |||
* @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 chanjarster.weixin.bean.WxXmlMessage; | |||
import chanjarster.weixin.bean.WxXmlOutMessage; | |||
/** | |||
* <pre> | |||
@@ -55,7 +56,7 @@ public class WxMessageRouter { | |||
* 处理微信消息 | |||
* @param wxMessage | |||
*/ | |||
public WxXmlMessage route(final WxXmlMessage wxMessage) { | |||
public WxXmlOutMessage route(final WxXmlMessage wxMessage) { | |||
final List<Rule> matchRules = new ArrayList<Rule>(); | |||
// 收集匹配的规则 | |||
for (final Rule rule : rules) { | |||
@@ -84,7 +85,7 @@ public class WxMessageRouter { | |||
return null; | |||
} | |||
WxXmlMessage res = null; | |||
WxXmlOutMessage res = null; | |||
for (final Rule rule : matchRules) { | |||
// 返回最后一个匹配规则的结果 | |||
res = rule.service(wxMessage); | |||
@@ -254,7 +255,7 @@ public class WxMessageRouter { | |||
* @param wxMessage | |||
* @return true 代表继续执行别的router,false 代表停止执行别的router | |||
*/ | |||
protected WxXmlMessage service(WxXmlMessage wxMessage) { | |||
protected WxXmlOutMessage service(WxXmlMessage wxMessage) { | |||
Map<String, Object> context = new HashMap<String, Object>(); | |||
// 如果拦截器不通过 | |||
for (WxMessageInterceptor interceptor : this.interceptors) { | |||
@@ -264,7 +265,7 @@ public class WxMessageRouter { | |||
} | |||
// 交给handler处理 | |||
WxXmlMessage res = null; | |||
WxXmlOutMessage res = null; | |||
for (WxMessageHandler handler : this.handlers) { | |||
// 返回最后handler的结果 | |||
res = handler.handle(wxMessage, context); | |||
@@ -132,19 +132,19 @@ public class WxXmlMessage { | |||
/** | |||
* group_id下粉丝数;或者openid_list中的粉丝数 | |||
*/ | |||
private int TotalCount; | |||
private Integer TotalCount; | |||
/** | |||
* 过滤(过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超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() { | |||
return ToUserName; | |||
@@ -340,14 +340,6 @@ public class WxXmlMessage { | |||
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) { | |||
try { | |||
return XmlTransformer.fromXml(WxXmlMessage.class, xml); | |||
@@ -370,28 +362,28 @@ public class WxXmlMessage { | |||
public void setStatus(String status) { | |||
Status = status; | |||
} | |||
public int getTotalCount() { | |||
public Integer getTotalCount() { | |||
return TotalCount; | |||
} | |||
public void setTotalCount(int totalCount) { | |||
public void setTotalCount(Integer totalCount) { | |||
TotalCount = totalCount; | |||
} | |||
public int getFilterCount() { | |||
public Integer getFilterCount() { | |||
return FilterCount; | |||
} | |||
public void setFilterCount(int filterCount) { | |||
public void setFilterCount(Integer filterCount) { | |||
FilterCount = filterCount; | |||
} | |||
public int getSentCount() { | |||
public Integer getSentCount() { | |||
return SentCount; | |||
} | |||
public void setSentCount(int sentCount) { | |||
public void setSentCount(Integer sentCount) { | |||
SentCount = sentCount; | |||
} | |||
public int getErrorCount() { | |||
public Integer getErrorCount() { | |||
return ErrorCount; | |||
} | |||
public void setErrorCount(int errorCount) { | |||
public void setErrorCount(Integer errorCount) { | |||
ErrorCount = errorCount; | |||
} | |||
@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 chanjarster.weixin.bean.WxXmlMessage; | |||
import chanjarster.weixin.bean.WxXmlOutMessage; | |||
/** | |||
* 测试消息路由器 | |||
@@ -65,7 +66,7 @@ public class WxMessageRouterTest { | |||
final WxMessageRouter router = new WxMessageRouter(); | |||
router.rule().handler(new WxMessageHandler() { | |||
@Override | |||
public WxXmlMessage handle(WxXmlMessage wxMessage, Map<String, Object> context) { | |||
public WxXmlOutMessage handle(WxXmlMessage wxMessage, Map<String, Object> context) { | |||
// TODO Auto-generated method stub | |||
return null; | |||
} | |||
@@ -144,7 +145,7 @@ public class WxMessageRouterTest { | |||
} | |||
@Override | |||
public WxXmlMessage handle(WxXmlMessage wxMessage, Map<String, Object> context) { | |||
public WxXmlOutMessage handle(WxXmlMessage wxMessage, Map<String, Object> context) { | |||
sb.append(this.echoStr).append(','); | |||
return null; | |||
} | |||
@@ -61,33 +61,4 @@ public class WxXmlMessageTest { | |||
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", "")); | |||
} | |||
} |