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