| @@ -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", "")); | |||
| } | |||
| } | |||