diff --git a/.gitignore b/.gitignore index ba4f93dc..740251ba 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,6 @@ target .project .classpath -src/test/resources/test-config.xml sw-pom.xml *.iml +test-config.xml diff --git a/README.md b/README.md index c8f2c57b..6ab18863 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,34 @@ -weixin-java-tools +weixin-java-cp =========== -微信java开发工具集,本项目主要分为两大块:微信消息路由器、微信Java API +微信公众号、企业号Java SDK。 -特性列表: - -1. 不基于Servlet、和其他MVC框架,仅作为工具使用,提供更多的灵活性 -2. 详尽的单元测试代码,可以拿来当example用 -3. 详尽的javadoc -4. access token过期自动刷新的功能 -5. 微信服务端繁忙自动重试的功能 -6. 提供微信错误信息的异常处理机制 +从``1.0.3``开始,本项目拆分成3个部分: +1. weixin-java-common,公共lib +2. weixin-java-cp,企业号SDK +3. weixin-java-mp,公众号(订阅号、服务号)SDK 详细文档请看 [wiki](https://github.com/chanjarster/weixin-java-tools/wiki) -# Quickstart +# Quick Start + +如果要开发公众号(订阅号、服务号)应用,在你的maven项目中添加: -在你的maven项目中添加: ```xml me.chanjar - weixin-java-tools - 1.0.2 + weixin-java-mp + 1.0.3 ``` -## Hello World -```java -WxConfigStorage config = new WxInMemoryConfigStorage(); -config.setAppId(...); // 设置微信公众号的appid -config.setSecret(...); // 设置微信公众号的app secret -config.setToken(...); // 设置微信公众号的token - -WxServiceImpl wxService = new WxServiceImpl(); -wxService.setWxConfigStorage(config); - -// 用户的openid在下面地址获得 -// https://mp.weixin.qq.com/debug/cgi-bin/apiinfo?t=index&type=用户管理&form=获取关注者列表接口%20/user/get -String openid = ...; -WxCustomMessage message = WxCustomMessage.TEXT().toUser(openid).content("Hello World").build(); -wxService.customMessageSend(message); +如果要开发企业号应用,在你的maven项目中添加: + +```xml + + me.chanjar + weixin-java-cp + 1.0.3 + ``` diff --git a/pom.xml b/pom.xml index 0a334591..cd72620e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,10 +4,11 @@ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 4.0.0 me.chanjar - weixin-java-tools - 1.0.2 - WeiXin Java Tools - 用于开发微信公众号的Java工具 + weixin-java-parent + 1.0.3-SNAPSHOT + pom + WeiXin Java Tools - Parent + 微信公众号、企业号上级POM https://github.com/chanjarster/weixin-java-tools @@ -30,19 +31,20 @@ https://github.com/chanjarster/weixin-java-tools + + weixin-java-common + weixin-java-cp + weixin-java-mp + + UTF-8 true true 4.3.5 + - - junit - junit - 4.11 - test - org.apache.httpcomponents fluent-hc @@ -63,34 +65,11 @@ jaxb-impl 2.2.7 - - org.apache.oltu.oauth2 - org.apache.oltu.oauth2.client - 1.0.0 - com.google.code.gson gson 2.2.2 - - org.testng - testng - 6.8.7 - test - - - org.mockito - mockito-all - 1.9.5 - test - - - com.google.inject - guice - 3.0 - test - org.apache.commons commons-lang3 @@ -106,20 +85,49 @@ commons-io 2.4 - - org.eclipse.jetty - jetty-server - 9.3.0.M0 - test - - - org.eclipse.jetty - jetty-servlet - 9.3.0.M0 - test - + + + + junit + junit + 4.11 + test + + + com.google.inject + guice + 3.0 + test + + + org.testng + testng + 6.8.7 + test + + + org.mockito + mockito-all + 1.9.5 + test + + + org.eclipse.jetty + jetty-server + 9.3.0.M0 + test + + + org.eclipse.jetty + jetty-servlet + 9.3.0.M0 + test + + + + ossrh @@ -186,17 +194,17 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.17 + + + + - - org.apache.maven.plugins - maven-surefire-plugin - 2.17 - - - src/test/resources/testng.xml - - - org.sonatype.plugins nexus-staging-maven-plugin diff --git a/src/main/java/me/chanjar/weixin/bean/WxAccessToken.java b/src/main/java/me/chanjar/weixin/bean/WxAccessToken.java deleted file mode 100644 index ecd6b3aa..00000000 --- a/src/main/java/me/chanjar/weixin/bean/WxAccessToken.java +++ /dev/null @@ -1,31 +0,0 @@ -package me.chanjar.weixin.bean; - -import me.chanjar.weixin.util.json.WxGsonBuilder; - -public class WxAccessToken { - - private String access_token; - - private int expires_in; - - public String getAccess_token() { - return access_token; - } - - public void setAccess_token(String access_token) { - this.access_token = access_token; - } - - public int getExpires_in() { - return expires_in; - } - - public void setExpires_in(int expires_in) { - this.expires_in = expires_in; - } - - public static WxAccessToken fromJson(String json) { - return WxGsonBuilder.create().fromJson(json, WxAccessToken.class); - } - -} diff --git a/src/main/java/me/chanjar/weixin/bean/WxMassGroupMessage.java b/src/main/java/me/chanjar/weixin/bean/WxMassGroupMessage.java deleted file mode 100644 index d52120f4..00000000 --- a/src/main/java/me/chanjar/weixin/bean/WxMassGroupMessage.java +++ /dev/null @@ -1,70 +0,0 @@ -package me.chanjar.weixin.bean; - -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.util.json.WxGsonBuilder; - -/** - * 分组群发的消息 - * - * @author chanjarster - */ -public class WxMassGroupMessage { - - private long group_id; - private String msgtype; - private String content; - private String media_id; - - public WxMassGroupMessage() { - super(); - } - - public String getMsgtype() { - return msgtype; - } - - /** - *
-   * 请使用
-   * {@link WxConsts#MASS_MSG_IMAGE}
-   * {@link WxConsts#MASS_MSG_NEWS}
-   * {@link WxConsts#MASS_MSG_TEXT}
-   * {@link WxConsts#MASS_MSG_VIDEO}
-   * {@link WxConsts#MASS_MSG_VOICE}
-   * 如果msgtype和media_id不匹配的话,会返回系统繁忙的错误
-   * 
- * @param msgtype - */ - public void setMsgtype(String msgtype) { - this.msgtype = msgtype; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - public String getMedia_id() { - return media_id; - } - - public void setMedia_id(String media_id) { - this.media_id = media_id; - } - - public String toJson() { - return WxGsonBuilder.INSTANCE.create().toJson(this); - } - - public long getGroup_id() { - return group_id; - } - - public void setGroup_id(long group_id) { - this.group_id = group_id; - } - -} diff --git a/src/main/java/me/chanjar/weixin/bean/WxMassOpenIdsMessage.java b/src/main/java/me/chanjar/weixin/bean/WxMassOpenIdsMessage.java deleted file mode 100644 index 2619672f..00000000 --- a/src/main/java/me/chanjar/weixin/bean/WxMassOpenIdsMessage.java +++ /dev/null @@ -1,79 +0,0 @@ -package me.chanjar.weixin.bean; - -import java.util.ArrayList; -import java.util.List; - -import me.chanjar.weixin.util.json.WxGsonBuilder; - -/** - * OpenId列表群发的消息 - * - * @author chanjarster - */ -public class WxMassOpenIdsMessage { - - private List touser = new ArrayList(); - private String msgtype; - private String content; - private String media_id; - - public WxMassOpenIdsMessage() { - super(); - } - - public String getMsgtype() { - return msgtype; - } - - /** - *
-   * 请使用
-   * {@link me.chanjar.weixin.api.WxConsts#MASS_MSG_IMAGE}
-   * {@link me.chanjar.weixin.api.WxConsts#MASS_MSG_NEWS}
-   * {@link me.chanjar.weixin.api.WxConsts#MASS_MSG_TEXT}
-   * {@link me.chanjar.weixin.api.WxConsts#MASS_MSG_VIDEO}
-   * {@link me.chanjar.weixin.api.WxConsts#MASS_MSG_VOICE}
-   * 如果msgtype和media_id不匹配的话,会返回系统繁忙的错误
-   * 
- * @param msgtype - */ - public void setMsgtype(String msgtype) { - this.msgtype = msgtype; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - public String getMedia_id() { - return media_id; - } - - public void setMedia_id(String media_id) { - this.media_id = media_id; - } - - public String toJson() { - return WxGsonBuilder.INSTANCE.create().toJson(this); - } - - /** - * OpenId列表,最多支持10,000个 - * @return - */ - public List getTouser() { - return touser; - } - - /** - * 添加OpenId,最多支持10,000个 - * @param openId - */ - public void addUser(String openId) { - this.touser.add(openId); - } -} diff --git a/src/main/java/me/chanjar/weixin/bean/WxXmlMessage.java b/src/main/java/me/chanjar/weixin/bean/WxXmlMessage.java deleted file mode 100644 index 67fe1bbd..00000000 --- a/src/main/java/me/chanjar/weixin/bean/WxXmlMessage.java +++ /dev/null @@ -1,457 +0,0 @@ -package me.chanjar.weixin.bean; - -import me.chanjar.weixin.api.WxConfigStorage; -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.util.crypto.WxCryptUtil; -import me.chanjar.weixin.util.xml.AdapterCDATA; -import me.chanjar.weixin.util.xml.XmlTransformer; -import org.apache.commons.io.IOUtils; - -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 java.io.IOException; -import java.io.InputStream; - -/** - *
- * 微信推送过来的消息,也是同步回复给用户的消息,xml格式
- * 相关字段的解释看微信开发者文档:
- * http://mp.weixin.qq.com/wiki/index.php?title=接收普通消息
- * http://mp.weixin.qq.com/wiki/index.php?title=接收事件推送
- * http://mp.weixin.qq.com/wiki/index.php?title=接收语音识别结果
- * 
- * - * @author chanjarster - */ -@XmlRootElement(name = "xml") -@XmlAccessorType(XmlAccessType.FIELD) -public class WxXmlMessage { - - /////////////////////// - // 以下都是微信推送过来的消息的xml的element所对应的属性 - /////////////////////// - - @XmlElement(name = "ToUserName") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String ToUserName; - - @XmlElement(name = "FromUserName") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String FromUserName; - - @XmlElement(name = "CreateTime") - private Long CreateTime; - - @XmlElement(name = "MsgType") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String MsgType; - - @XmlElement(name = "Content") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Content; - - @XmlElement(name = "MsgId") - private Long MsgId; - - @XmlElement(name = "PicUrl") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String PicUrl; - - @XmlElement(name = "MediaId") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String MediaId; - - @XmlElement(name = "Format") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Format; - - @XmlElement(name = "ThumbMediaId") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String ThumbMediaId; - - @XmlElement(name = "Location_X") - private Double Location_X; - - @XmlElement(name = "Location_Y") - private Double Location_Y; - - @XmlElement(name = "Scale") - private Double Scale; - - @XmlElement(name = "Label") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Label; - - @XmlElement(name = "Title") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Title; - - @XmlElement(name = "Description") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Description; - - @XmlElement(name = "Url") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Url; - - @XmlElement(name = "Event") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Event; - - @XmlElement(name = "EventKey") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String EventKey; - - @XmlElement(name = "Ticket") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Ticket; - - @XmlElement(name = "Latitude") - private Double Latitude; - - @XmlElement(name = "Longitude") - private Double Longitude; - - @XmlElement(name = "Precision") - private Double Precision; - - @XmlElement(name = "Recognition") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Recognition; - - /////////////////////////////////////// - // 群发消息返回的结果 - /////////////////////////////////////// - /** - * 群发的结果 - */ - @XmlElement(name = "Status") - @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Status; - /** - * group_id下粉丝数;或者openid_list中的粉丝数 - */ - private Integer TotalCount; - /** - * 过滤(过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超4条的过滤)后,准备发送的粉丝数,原则上,FilterCount = SentCount + ErrorCount - */ - private Integer FilterCount; - /** - * 发送成功的粉丝数 - */ - private Integer SentCount; - /** - * 发送失败的粉丝数 - */ - private Integer ErrorCount; - - public String getToUserName() { - return ToUserName; - } - - public void setToUserName(String toUserName) { - ToUserName = toUserName; - } - - public Long getCreateTime() { - return CreateTime; - } - - public void setCreateTime(Long createTime) { - CreateTime = createTime; - } - - /** - *
-   * 当接受用户消息时,可能会获得以下值:
-   * {@link WxConsts#XML_MSG_TEXT}
-   * {@link WxConsts#XML_MSG_IMAGE}
-   * {@link WxConsts#XML_MSG_VOICE}
-   * {@link WxConsts#XML_MSG_VIDEO}
-   * {@link WxConsts#XML_MSG_LOCATION}
-   * {@link WxConsts#XML_MSG_LINK}
-   * {@link WxConsts#XML_MSG_EVENT}
-   * 
- * - * @return - */ - public String getMsgType() { - return MsgType; - } - - /** - *
-   * 当发送消息的时候使用:
-   * {@link WxConsts#XML_MSG_TEXT}
-   * {@link WxConsts#XML_MSG_IMAGE}
-   * {@link WxConsts#XML_MSG_VOICE}
-   * {@link WxConsts#XML_MSG_VIDEO}
-   * {@link WxConsts#XML_MSG_NEWS}
-   * {@link WxConsts#XML_MSG_MUSIC}
-   * 
- * - * @param msgType - */ - public void setMsgType(String msgType) { - MsgType = msgType; - } - - public String getContent() { - return Content; - } - - public void setContent(String content) { - Content = content; - } - - public Long getMsgId() { - return MsgId; - } - - public void setMsgId(Long msgId) { - MsgId = msgId; - } - - public String getPicUrl() { - return PicUrl; - } - - public void setPicUrl(String picUrl) { - PicUrl = picUrl; - } - - public String getMediaId() { - return MediaId; - } - - public void setMediaId(String mediaId) { - MediaId = mediaId; - } - - public String getFormat() { - return Format; - } - - public void setFormat(String format) { - Format = format; - } - - public String getThumbMediaId() { - return ThumbMediaId; - } - - public void setThumbMediaId(String thumbMediaId) { - ThumbMediaId = thumbMediaId; - } - - public Double getLocation_X() { - return Location_X; - } - - public void setLocation_X(Double location_X) { - Location_X = location_X; - } - - public Double getLocation_Y() { - return Location_Y; - } - - public void setLocation_Y(Double location_Y) { - Location_Y = location_Y; - } - - public Double getScale() { - return Scale; - } - - public void setScale(Double scale) { - Scale = scale; - } - - public String getLabel() { - return Label; - } - - public void setLabel(String label) { - Label = label; - } - - public String getTitle() { - return Title; - } - - public void setTitle(String title) { - Title = title; - } - - public String getDescription() { - return Description; - } - - public void setDescription(String description) { - Description = description; - } - - public String getUrl() { - return Url; - } - - public void setUrl(String url) { - Url = url; - } - - public String getEvent() { - return Event; - } - - public void setEvent(String event) { - Event = event; - } - - public String getEventKey() { - return EventKey; - } - - public void setEventKey(String eventKey) { - EventKey = eventKey; - } - - public String getTicket() { - return Ticket; - } - - public void setTicket(String ticket) { - Ticket = ticket; - } - - public Double getLatitude() { - return Latitude; - } - - public void setLatitude(Double latitude) { - Latitude = latitude; - } - - public Double getLongitude() { - return Longitude; - } - - public void setLongitude(Double longitude) { - Longitude = longitude; - } - - public Double getPrecision() { - return Precision; - } - - public void setPrecision(Double precision) { - Precision = precision; - } - - public String getRecognition() { - return Recognition; - } - - public void setRecognition(String recognition) { - Recognition = recognition; - } - - public String getFromUserName() { - return FromUserName; - } - - public void setFromUserName(String fromUserName) { - FromUserName = fromUserName; - } - - public static WxXmlMessage fromXml(String xml) { - try { - return XmlTransformer.fromXml(WxXmlMessage.class, xml); - } catch (JAXBException e) { - throw new RuntimeException(e); - } - } - - public static WxXmlMessage fromXml(InputStream is) { - try { - return XmlTransformer.fromXml(WxXmlMessage.class, is); - } catch (JAXBException e) { - throw new RuntimeException(e); - } - } - - /** - * 从加密字符串转换 - * - * @param encryptedXml - * @param wxConfigStorage - * @param timestamp - * @param nonce - * @param msgSignature - * @return - */ - public static WxXmlMessage fromEncryptedXml( - String encryptedXml, - WxConfigStorage wxConfigStorage, - String timestamp, String nonce, String msgSignature) { - WxCryptUtil cryptUtil = new WxCryptUtil(wxConfigStorage); - String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml); - return fromXml(plainText); - } - - public static WxXmlMessage fromEncryptedXml( - InputStream is, - WxConfigStorage wxConfigStorage, - String timestamp, String nonce, String msgSignature) { - try { - return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxConfigStorage, timestamp, nonce, msgSignature); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public String getStatus() { - return Status; - } - - public void setStatus(String status) { - Status = status; - } - - public Integer getTotalCount() { - return TotalCount; - } - - public void setTotalCount(Integer totalCount) { - TotalCount = totalCount; - } - - public Integer getFilterCount() { - return FilterCount; - } - - public void setFilterCount(Integer filterCount) { - FilterCount = filterCount; - } - - public Integer getSentCount() { - return SentCount; - } - - public void setSentCount(Integer sentCount) { - SentCount = sentCount; - } - - public Integer getErrorCount() { - return ErrorCount; - } - - public void setErrorCount(Integer errorCount) { - ErrorCount = errorCount; - } - -} diff --git a/src/main/java/me/chanjar/weixin/bean/custombuilder/BaseBuilder.java b/src/main/java/me/chanjar/weixin/bean/custombuilder/BaseBuilder.java deleted file mode 100644 index 9cf19aaf..00000000 --- a/src/main/java/me/chanjar/weixin/bean/custombuilder/BaseBuilder.java +++ /dev/null @@ -1,20 +0,0 @@ -package me.chanjar.weixin.bean.custombuilder; - -import me.chanjar.weixin.bean.WxCustomMessage; - -public class BaseBuilder { - protected String msgtype; - protected String toUser; - - public T toUser(String toUser) { - this.toUser = toUser; - return (T) this; - } - - public WxCustomMessage build() { - WxCustomMessage m = new WxCustomMessage(); - m.setMsgtype(this.msgtype); - m.setTouser(this.toUser); - return m; - } -} diff --git a/src/main/java/me/chanjar/weixin/bean/custombuilder/ImageBuilder.java b/src/main/java/me/chanjar/weixin/bean/custombuilder/ImageBuilder.java deleted file mode 100644 index 3336d2b1..00000000 --- a/src/main/java/me/chanjar/weixin/bean/custombuilder/ImageBuilder.java +++ /dev/null @@ -1,31 +0,0 @@ -package me.chanjar.weixin.bean.custombuilder; - -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.bean.WxCustomMessage; - -/** - * 获得消息builder - *
- * 用法: WxCustomMessage m = WxCustomMessage.IMAGE().media_id(...).touser(...).build();
- * 
- * @author chanjarster - * - */ -public final class ImageBuilder extends BaseBuilder { - private String media_id; - - public ImageBuilder() { - this.msgtype = WxConsts.CUSTOM_MSG_IMAGE; - } - - public ImageBuilder mediaId(String media_id) { - this.media_id = media_id; - return this; - } - - public WxCustomMessage build() { - WxCustomMessage m = super.build(); - m.setMedia_id(this.media_id); - return m; - } -} diff --git a/src/main/java/me/chanjar/weixin/bean/custombuilder/MusicBuilder.java b/src/main/java/me/chanjar/weixin/bean/custombuilder/MusicBuilder.java deleted file mode 100644 index f6f7041a..00000000 --- a/src/main/java/me/chanjar/weixin/bean/custombuilder/MusicBuilder.java +++ /dev/null @@ -1,64 +0,0 @@ -package me.chanjar.weixin.bean.custombuilder; - -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.bean.WxCustomMessage; - -/** - * 音乐消息builder - *
- * 用法: WxCustomMessage m = WxCustomMessage.MUSIC()
- *                      .musicurl(...)
- *                      .hqmusicurl(...)
- *                      .title(...)
- *                      .thumb_media_id(..)
- *                      .description(..)
- *                      .touser(...)
- *                      .build();
- * 
- */ -public final class MusicBuilder extends BaseBuilder { - private String title; - private String description; - private String thumb_media_id; - private String musicurl; - private String hqmusicurl; - - public MusicBuilder() { - this.msgtype = WxConsts.CUSTOM_MSG_MUSIC; - } - - public MusicBuilder musicUrl(String musicurl) { - this.musicurl = musicurl; - return this; - } - - public MusicBuilder hqmusicUrl(String hqmusicurl) { - this.hqmusicurl = hqmusicurl; - return this; - } - - public MusicBuilder title(String title) { - this.title = title; - return this; - } - - public MusicBuilder description(String description) { - this.description = description; - return this; - } - - public MusicBuilder thumbMediaId(String thumb_media_id) { - this.thumb_media_id = thumb_media_id; - return this; - } - - public WxCustomMessage build() { - WxCustomMessage m = super.build(); - m.setMusicurl(this.musicurl); - m.setHqmusicurl(this.hqmusicurl); - m.setTitle(title); - m.setDescription(description); - m.setThumb_media_id(thumb_media_id); - return m; - } -} diff --git a/src/main/java/me/chanjar/weixin/bean/custombuilder/NewsBuilder.java b/src/main/java/me/chanjar/weixin/bean/custombuilder/NewsBuilder.java deleted file mode 100644 index 33a630da..00000000 --- a/src/main/java/me/chanjar/weixin/bean/custombuilder/NewsBuilder.java +++ /dev/null @@ -1,36 +0,0 @@ -package me.chanjar.weixin.bean.custombuilder; - -import java.util.ArrayList; -import java.util.List; - -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.bean.WxCustomMessage; - -/** - * 图文消息builder - *
- * 用法:
- * WxCustomMessage m = WxCustomMessage.NEWS().addArticle(article).touser(...).build();
- * 
- * @author chanjarster - * - */ -public final class NewsBuilder extends BaseBuilder { - - private List articles = new ArrayList(); - - public NewsBuilder() { - this.msgtype = WxConsts.CUSTOM_MSG_NEWS; - } - - public NewsBuilder addArticle(WxCustomMessage.WxArticle article) { - this.articles.add(article); - return this; - } - - public WxCustomMessage build() { - WxCustomMessage m = super.build(); - m.setArticles(this.articles); - return m; - } -} diff --git a/src/main/java/me/chanjar/weixin/bean/custombuilder/VoiceBuilder.java b/src/main/java/me/chanjar/weixin/bean/custombuilder/VoiceBuilder.java deleted file mode 100644 index cf320d64..00000000 --- a/src/main/java/me/chanjar/weixin/bean/custombuilder/VoiceBuilder.java +++ /dev/null @@ -1,31 +0,0 @@ -package me.chanjar.weixin.bean.custombuilder; - -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.bean.WxCustomMessage; - -/** - * 语音消息builder - *
- * 用法: WxCustomMessage m = WxCustomMessage.VOICE().media_id(...).touser(...).build();
- * 
- * @author chanjarster - * - */ -public final class VoiceBuilder extends BaseBuilder { - private String media_id; - - public VoiceBuilder() { - this.msgtype = WxConsts.CUSTOM_MSG_VOICE; - } - - public VoiceBuilder mediaId(String media_id) { - this.media_id = media_id; - return this; - } - - public WxCustomMessage build() { - WxCustomMessage m = super.build(); - m.setMedia_id(this.media_id); - return m; - } -} diff --git a/src/main/java/me/chanjar/weixin/bean/result/WxError.java b/src/main/java/me/chanjar/weixin/bean/result/WxError.java deleted file mode 100644 index 7f944720..00000000 --- a/src/main/java/me/chanjar/weixin/bean/result/WxError.java +++ /dev/null @@ -1,136 +0,0 @@ -package me.chanjar.weixin.bean.result; - -import java.util.HashMap; -import java.util.Map; - -import me.chanjar.weixin.util.json.WxGsonBuilder; - -/** - * 微信错误码说明 - * http://mp.weixin.qq.com/wiki/index.php?title=全局返回码说明 - * @author chanjarster - * - */ -public class WxError { - - protected static final Map errMap = new HashMap(); - - static { - errMap.put(-1, "系统繁忙"); - errMap.put(0, "请求成功"); - errMap.put(40001, "获取access_token时AppSecret错误,或者access_token无效"); - errMap.put(40002, "不合法的凭证类型"); - errMap.put(40003, "不合法的OpenID"); - errMap.put(40004, "不合法的媒体文件类型"); - errMap.put(40005, "不合法的文件类型"); - errMap.put(40006, "不合法的文件大小"); - errMap.put(40007, "不合法的媒体文件id"); - errMap.put(40008, "不合法的消息类型"); - errMap.put(40009, "不合法的图片文件大小"); - errMap.put(40010, "不合法的语音文件大小"); - errMap.put(40011, "不合法的视频文件大小"); - errMap.put(40012, "不合法的缩略图文件大小"); - errMap.put(40013, "不合法的APPID"); - errMap.put(40014, "不合法的access_token"); - errMap.put(40015, "不合法的菜单类型"); - errMap.put(40016, "不合法的按钮个数"); - errMap.put(40017, "不合法的按钮个数"); - errMap.put(40018, "不合法的按钮名字长度"); - errMap.put(40019, "不合法的按钮KEY长度"); - errMap.put(40020, "不合法的按钮URL长度"); - errMap.put(40021, "不合法的菜单版本号"); - errMap.put(40022, "不合法的子菜单级数"); - errMap.put(40023, "不合法的子菜单按钮个数"); - errMap.put(40024, "不合法的子菜单按钮类型"); - errMap.put(40025, "不合法的子菜单按钮名字长度"); - errMap.put(40026, "不合法的子菜单按钮KEY长度"); - errMap.put(40027, "不合法的子菜单按钮URL长度"); - errMap.put(40028, "不合法的自定义菜单使用用户"); - errMap.put(40029, "不合法的oauth_code"); - errMap.put(40030, "不合法的refresh_token"); - errMap.put(40031, "不合法的openid列表"); - errMap.put(40032, "不合法的openid列表长度"); - errMap.put(40033, "不合法的请求字符,不能包含\\uxxxx格式的字符"); - errMap.put(40035, "不合法的参数"); - errMap.put(40038, "不合法的请求格式"); - errMap.put(40039, "不合法的URL长度"); - errMap.put(40050, "不合法的分组id"); - errMap.put(40051, "分组名字不合法"); - errMap.put(41001, "缺少access_token参数"); - errMap.put(41002, "缺少appid参数"); - errMap.put(41003, "缺少refresh_token参数"); - errMap.put(41004, "缺少secret参数"); - errMap.put(41005, "缺少多媒体文件数据"); - errMap.put(41006, "缺少media_id参数"); - errMap.put(41007, "缺少子菜单数据"); - errMap.put(41008, "缺少oauth code"); - errMap.put(41009, "缺少openid"); - errMap.put(42001, "access_token超时"); - errMap.put(42002, "refresh_token超时"); - errMap.put(42003, "oauth_code超时"); - errMap.put(43001, "需要GET请求"); - errMap.put(43002, "需要POST请求"); - errMap.put(43003, "需要HTTPS请求"); - errMap.put(43004, "需要接收者关注"); - errMap.put(43005, "需要好友关系"); - errMap.put(44001, "多媒体文件为空"); - errMap.put(44002, "POST的数据包为空"); - errMap.put(44003, "图文消息内容为空"); - errMap.put(44004, "文本消息内容为空"); - errMap.put(45001, "多媒体文件大小超过限制"); - errMap.put(45002, "消息内容超过限制"); - errMap.put(45003, "标题字段超过限制"); - errMap.put(45004, "描述字段超过限制"); - errMap.put(45005, "链接字段超过限制"); - errMap.put(45006, "图片链接字段超过限制"); - errMap.put(45007, "语音播放时间超过限制"); - errMap.put(45008, "图文消息超过限制"); - errMap.put(45009, "接口调用超过限制"); - errMap.put(45010, "创建菜单个数超过限制"); - errMap.put(45015, "回复时间超过限制"); - errMap.put(45016, "系统分组,不允许修改"); - errMap.put(45017, "分组名字过长"); - errMap.put(45018, "分组数量超过上限"); - errMap.put(46001, "不存在媒体数据"); - errMap.put(46002, "不存在的菜单版本"); - errMap.put(46003, "不存在的菜单数据"); - errMap.put(46004, "不存在的用户"); - errMap.put(47001, "解析JSON/XML内容错误"); - errMap.put(48001, "api功能未授权"); - errMap.put(50001, "用户未授权该api"); - } - - protected int errcode; - - protected String errmsg; - - public int getErrcode() { - return errcode; - } - - public void setErrcode(int errcode) { - this.errcode = errcode; - } - - public String getErrmsg() { - return errmsg; - } - - public void setErrmsg(String errmsg) { - this.errmsg = errmsg; - } - - public String getDescription() { - return errMap.get(errcode); - } - - public static WxError fromJson(String json) { - return WxGsonBuilder.create().fromJson(json, WxError.class); - } - - @Override - public String toString() { - return "微信错误 errcode=" + errcode + ", errmsg=" + errmsg + ", description=" + getDescription(); - } - -} diff --git a/src/main/java/me/chanjar/weixin/bean/result/WxMassSendResult.java b/src/main/java/me/chanjar/weixin/bean/result/WxMassSendResult.java deleted file mode 100644 index b3c0a349..00000000 --- a/src/main/java/me/chanjar/weixin/bean/result/WxMassSendResult.java +++ /dev/null @@ -1,55 +0,0 @@ -package me.chanjar.weixin.bean.result; - -import me.chanjar.weixin.util.json.WxGsonBuilder; - -/** - *
- * 群发消息一发送就返回的结果
- * 
- * 真正的群发消息是否发送成功要看
- * http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口#.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81.E7.BE.A4.E5.8F.91.E7.BB.93.E6.9E.9C
- * 
- * 
- * @author chanjarster - * - */ -public class WxMassSendResult { - - private String errcode; - private String errmsg; - private String msg_id; - - public String getErrcode() { - return errcode; - } - - public void setErrcode(String errcode) { - this.errcode = errcode; - } - - public String getErrmsg() { - return errmsg; - } - - public void setErrmsg(String errmsg) { - this.errmsg = errmsg; - } - - public String getMsg_id() { - return msg_id; - } - - public void setMsg_id(String msg_id) { - this.msg_id = msg_id; - } - - public static WxMassSendResult fromJson(String json) { - return WxGsonBuilder.create().fromJson(json, WxMassSendResult.class); - } - - @Override - public String toString() { - return "WxMassSendResult [errcode=" + errcode + ", errmsg=" + errmsg + ", msg_id=" + msg_id + "]"; - } - -} diff --git a/src/main/java/me/chanjar/weixin/bean/result/WxMassUploadResult.java b/src/main/java/me/chanjar/weixin/bean/result/WxMassUploadResult.java deleted file mode 100644 index f12a2bd0..00000000 --- a/src/main/java/me/chanjar/weixin/bean/result/WxMassUploadResult.java +++ /dev/null @@ -1,52 +0,0 @@ -package me.chanjar.weixin.bean.result; - -import me.chanjar.weixin.util.json.WxGsonBuilder; - -/** - *
- * 上传群发用的素材的结果
- * 视频和图文消息需要在群发前上传素材
- * 
- * @author chanjarster - * - */ -public class WxMassUploadResult { - - private String type; - private String media_id; - private long created_at; - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getMedia_id() { - return media_id; - } - - public void setMedia_id(String media_id) { - this.media_id = media_id; - } - - public long getCreated_at() { - return created_at; - } - - public void setCreated_at(long created_at) { - this.created_at = created_at; - } - - public static WxMassUploadResult fromJson(String json) { - return WxGsonBuilder.create().fromJson(json, WxMassUploadResult.class); - } - - @Override - public String toString() { - return "WxUploadResult [type=" + type + ", media_id=" + media_id + ", created_at=" + created_at + "]"; - } - -} diff --git a/src/main/java/me/chanjar/weixin/bean/result/WxMediaUploadResult.java b/src/main/java/me/chanjar/weixin/bean/result/WxMediaUploadResult.java deleted file mode 100644 index ac0ba8e4..00000000 --- a/src/main/java/me/chanjar/weixin/bean/result/WxMediaUploadResult.java +++ /dev/null @@ -1,54 +0,0 @@ -package me.chanjar.weixin.bean.result; - -import me.chanjar.weixin.util.json.WxGsonBuilder; - -public class WxMediaUploadResult { - - private String type; - private String media_id; - private String thumb_media_id; - private long created_at; - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getMedia_id() { - return media_id; - } - - public void setMedia_id(String media_id) { - this.media_id = media_id; - } - - public long getCreated_at() { - return created_at; - } - - public void setCreated_at(long created_at) { - this.created_at = created_at; - } - - public static WxMediaUploadResult fromJson(String json) { - return WxGsonBuilder.create().fromJson(json, WxMediaUploadResult.class); - } - - public String getThumb_media_id() { - return thumb_media_id; - } - - public void setThumb_media_id(String thumb_media_id) { - this.thumb_media_id = thumb_media_id; - } - - @Override - public String toString() { - return "WxUploadResult [type=" + type + ", media_id=" + media_id + ", thumb_media_id=" + thumb_media_id - + ", created_at=" + created_at + "]"; - } - -} diff --git a/src/main/java/me/chanjar/weixin/bean/result/WxUserList.java b/src/main/java/me/chanjar/weixin/bean/result/WxUserList.java deleted file mode 100644 index 7b20b396..00000000 --- a/src/main/java/me/chanjar/weixin/bean/result/WxUserList.java +++ /dev/null @@ -1,48 +0,0 @@ -package me.chanjar.weixin.bean.result; - -import java.util.ArrayList; -import java.util.List; - -import me.chanjar.weixin.util.json.WxGsonBuilder; - - -/** - * 关注者列表 - * @author chanjarster - * - */ -public class WxUserList { - - protected int total = -1; - protected int count = -1; - protected List openids = new ArrayList(); - protected String next_openid; - public int getTotal() { - return total; - } - public void setTotal(int total) { - this.total = total; - } - public int getCount() { - return count; - } - public void setCount(int count) { - this.count = count; - } - public List getOpenids() { - return openids; - } - public void setOpenids(List openids) { - this.openids = openids; - } - public String getNext_openid() { - return next_openid; - } - public void setNext_openid(String next_openid) { - this.next_openid = next_openid; - } - - public static WxUserList fromJson(String json) { - return WxGsonBuilder.INSTANCE.create().fromJson(json, WxUserList.class); - } -} diff --git a/src/main/java/me/chanjar/weixin/util/json/WxGsonBuilder.java b/src/main/java/me/chanjar/weixin/util/json/WxGsonBuilder.java deleted file mode 100644 index a7342ce4..00000000 --- a/src/main/java/me/chanjar/weixin/util/json/WxGsonBuilder.java +++ /dev/null @@ -1,35 +0,0 @@ -package me.chanjar.weixin.util.json; - -import me.chanjar.weixin.bean.WxCustomMessage; -import me.chanjar.weixin.bean.WxGroup; -import me.chanjar.weixin.bean.WxMassGroupMessage; -import me.chanjar.weixin.bean.WxMassNews; -import me.chanjar.weixin.bean.WxMassOpenIdsMessage; -import me.chanjar.weixin.bean.WxMenu; -import me.chanjar.weixin.bean.result.WxUser; -import me.chanjar.weixin.bean.result.WxUserList; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -public class WxGsonBuilder { - - public static final GsonBuilder INSTANCE = new GsonBuilder(); - - static { - INSTANCE.disableHtmlEscaping(); - INSTANCE.registerTypeAdapter(WxCustomMessage.class, new WxCustomMessageGsonAdapter()); - INSTANCE.registerTypeAdapter(WxMenu.class, new WxMenuGsonAdapter()); - INSTANCE.registerTypeAdapter(WxMassNews.class, new WxMassNewsGsonAdapter()); - INSTANCE.registerTypeAdapter(WxMassGroupMessage.class, new WxMassMessageGsonAdapter()); - INSTANCE.registerTypeAdapter(WxMassOpenIdsMessage.class, new WxMassOpenIdsMessageGsonAdapter()); - INSTANCE.registerTypeAdapter(WxGroup.class, new WxGroupGsonAdapter()); - INSTANCE.registerTypeAdapter(WxUser.class, new WxUserGsonAdapter()); - INSTANCE.registerTypeAdapter(WxUserList.class, new WxUserListGsonAdapter()); - } - - public static Gson create() { - return INSTANCE.create(); - } - -} diff --git a/src/main/java/me/chanjar/weixin/util/json/WxMassOpenIdsMessageGsonAdapter.java b/src/main/java/me/chanjar/weixin/util/json/WxMassOpenIdsMessageGsonAdapter.java deleted file mode 100644 index 66033e9f..00000000 --- a/src/main/java/me/chanjar/weixin/util/json/WxMassOpenIdsMessageGsonAdapter.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. - * - * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended - * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction - * arose from modification of the original source, or other redistribution of this source - * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. - */ -package me.chanjar.weixin.util.json; - -import java.lang.reflect.Type; - -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.bean.WxMassOpenIdsMessage; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; - -/** - * - * @author qianjia - * - */ -public class WxMassOpenIdsMessageGsonAdapter implements JsonSerializer { - - public JsonElement serialize(WxMassOpenIdsMessage message, Type typeOfSrc, JsonSerializationContext context) { - JsonObject messageJson = new JsonObject(); - - JsonArray touser = new JsonArray(); - for (String openId : message.getTouser()) { - touser.add(new JsonPrimitive(openId)); - } - messageJson.add("touser", touser); - - if (WxConsts.MASS_MSG_NEWS.equals(message.getMsgtype())) { - JsonObject sub = new JsonObject(); - sub.addProperty("media_id", message.getMedia_id()); - messageJson.add(WxConsts.MASS_MSG_NEWS, sub); - } - if (WxConsts.MASS_MSG_TEXT.equals(message.getMsgtype())) { - JsonObject sub = new JsonObject(); - sub.addProperty("content", message.getContent()); - messageJson.add(WxConsts.MASS_MSG_TEXT, sub); - } - if (WxConsts.MASS_MSG_VOICE.equals(message.getMsgtype())) { - JsonObject sub = new JsonObject(); - sub.addProperty("media_id", message.getMedia_id()); - messageJson.add(WxConsts.MASS_MSG_VOICE, sub); - } - if (WxConsts.MASS_MSG_IMAGE.equals(message.getMsgtype())) { - JsonObject sub = new JsonObject(); - sub.addProperty("media_id", message.getMedia_id()); - messageJson.add(WxConsts.MASS_MSG_IMAGE, sub); - } - if (WxConsts.MASS_MSG_VIDEO.equals(message.getMsgtype())) { - JsonObject sub = new JsonObject(); - sub.addProperty("media_id", message.getMedia_id()); - messageJson.add(WxConsts.MASS_MSG_VIDEO, sub); - } - messageJson.addProperty("msgtype", message.getMsgtype()); - return messageJson; - } - -} diff --git a/src/main/java/me/chanjar/weixin/util/json/WxUserGsonAdapter.java b/src/main/java/me/chanjar/weixin/util/json/WxUserGsonAdapter.java deleted file mode 100644 index 4c2a6c4c..00000000 --- a/src/main/java/me/chanjar/weixin/util/json/WxUserGsonAdapter.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. - * - * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended - * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction - * arose from modification of the original source, or other redistribution of this source - * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. - */ -package me.chanjar.weixin.util.json; - -import java.lang.reflect.Type; - -import me.chanjar.weixin.bean.result.WxUser; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; - -/** - * - * @author qianjia - * - */ -public class WxUserGsonAdapter implements JsonDeserializer { - - public WxUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - JsonObject o = json.getAsJsonObject(); - WxUser wxUser = new WxUser(); - wxUser.setSubscribe(new Integer(0).equals(GsonHelper.getInteger(o, "subscribe")) ? false : true); - wxUser.setCity(GsonHelper.getString(o, "city")); - wxUser.setCountry(GsonHelper.getString(o, "country")); - wxUser.setHeadimgurl(GsonHelper.getString(o, "headimgurl")); - wxUser.setLanguage(GsonHelper.getString(o, "language")); - wxUser.setNickname(GsonHelper.getString(o, "nickname")); - wxUser.setOpenid(GsonHelper.getString(o, "openid")); - wxUser.setProvince(GsonHelper.getString(o, "province")); - wxUser.setSubscribe_time(GsonHelper.getLong(o, "subscribe_time")); - wxUser.setUnionid(GsonHelper.getString(o, "unionid")); - Integer sex = GsonHelper.getInteger(o, "sex"); - if(new Integer(1).equals(sex)) { - wxUser.setSex("男"); - } else if (new Integer(2).equals(sex)) { - wxUser.setSex("女"); - } else { - wxUser.setSex("未知"); - } - return wxUser; - } - -} diff --git a/src/main/java/me/chanjar/weixin/util/json/WxUserListGsonAdapter.java b/src/main/java/me/chanjar/weixin/util/json/WxUserListGsonAdapter.java deleted file mode 100644 index e865307f..00000000 --- a/src/main/java/me/chanjar/weixin/util/json/WxUserListGsonAdapter.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. - * - * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended - * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction - * arose from modification of the original source, or other redistribution of this source - * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. - */ -package me.chanjar.weixin.util.json; - -import java.lang.reflect.Type; - -import me.chanjar.weixin.bean.result.WxUserList; - -import com.google.gson.JsonArray; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; - -/** - * - * @author qianjia - * - */ -public class WxUserListGsonAdapter implements JsonDeserializer { - - public WxUserList deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - JsonObject o = json.getAsJsonObject(); - WxUserList wxUserList = new WxUserList(); - wxUserList.setTotal(GsonHelper.getInteger(o, "total")); - wxUserList.setCount(GsonHelper.getInteger(o, "count")); - wxUserList.setNext_openid(GsonHelper.getString(o, "next_openid")); - JsonArray data = o.get("data").getAsJsonObject().get("openid").getAsJsonArray(); - for (int i = 0; i < data.size(); i++) { - wxUserList.getOpenids().add(GsonHelper.getAsString(data.get(i))); - } - return wxUserList; - } - -} diff --git a/src/test/java/me/chanjar/weixin/api/WxCustomMessageAPITest.java b/src/test/java/me/chanjar/weixin/api/WxCustomMessageAPITest.java deleted file mode 100644 index da7e7bb0..00000000 --- a/src/test/java/me/chanjar/weixin/api/WxCustomMessageAPITest.java +++ /dev/null @@ -1,33 +0,0 @@ -package me.chanjar.weixin.api; - -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - -import me.chanjar.weixin.bean.WxCustomMessage; -import me.chanjar.weixin.exception.WxErrorException; - -import com.google.inject.Inject; - -/*** - * 测试发送客服消息 - * @author chanjarster - * - */ -@Test(groups="customMessageAPI", dependsOnGroups = "baseAPI") -@Guice(modules = ApiTestModule.class) -public class WxCustomMessageAPITest { - - @Inject - protected WxServiceImpl wxService; - - public void testSendCustomMessage() throws WxErrorException { - ApiTestModule.WxXmlConfigStorage configStorage = (ApiTestModule.WxXmlConfigStorage) wxService.wxConfigStorage; - WxCustomMessage message = new WxCustomMessage(); - message.setMsgtype(WxConsts.CUSTOM_MSG_TEXT); - message.setTouser(configStorage.getOpenId()); - message.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); - - wxService.customMessageSend(message); - } - -} diff --git a/src/test/java/me/chanjar/weixin/api/WxUserAPITest.java b/src/test/java/me/chanjar/weixin/api/WxUserAPITest.java deleted file mode 100644 index d2e351ed..00000000 --- a/src/test/java/me/chanjar/weixin/api/WxUserAPITest.java +++ /dev/null @@ -1,56 +0,0 @@ -package me.chanjar.weixin.api; - -import org.testng.Assert; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - -import me.chanjar.weixin.api.ApiTestModule.WxXmlConfigStorage; -import me.chanjar.weixin.bean.result.WxUser; -import me.chanjar.weixin.bean.result.WxUserList; -import me.chanjar.weixin.exception.WxErrorException; - -import com.google.inject.Inject; - -/** - * 测试用户相关的接口 - * @author chanjarster - * - */ -@Test(groups = "userAPI", dependsOnGroups = { "baseAPI", "groupAPI" }) -@Guice(modules = ApiTestModule.class) -public class WxUserAPITest { - - @Inject - protected WxServiceImpl wxService; - - public void testUserUpdateRemark() throws WxErrorException { - WxXmlConfigStorage configProvider = (WxXmlConfigStorage) wxService.wxConfigStorage; - wxService.userUpdateRemark(configProvider.getOpenId(), "测试备注名"); - } - - public void testUserInfo() throws WxErrorException { - WxXmlConfigStorage configProvider = (WxXmlConfigStorage) wxService.wxConfigStorage; - WxUser user = wxService.userInfo(configProvider.getOpenId(), null); - Assert.assertNotNull(user); - } - - public void testUserList() throws WxErrorException { - WxUserList wxUserList = wxService.userList(null); - Assert.assertNotNull(wxUserList); - Assert.assertFalse(wxUserList.getCount() == -1); - Assert.assertFalse(wxUserList.getTotal() == -1); - Assert.assertFalse(wxUserList.getOpenids().size() == -1); - } - - public void testGroupQueryUserGroup() throws WxErrorException { - WxXmlConfigStorage configStorage = (WxXmlConfigStorage) wxService.wxConfigStorage; - long groupid = wxService.userGetGroup(configStorage.getOpenId()); - Assert.assertTrue(groupid != -1l); - } - - public void getGroupMoveUser() throws WxErrorException { - WxXmlConfigStorage configStorage = (WxXmlConfigStorage) wxService.wxConfigStorage; - wxService.userUpdateGroup(configStorage.getOpenId(), wxService.groupGet().get(3).getId()); - } - -} diff --git a/src/test/resources/testng.xml b/src/test/resources/testng.xml deleted file mode 100644 index 2e15e341..00000000 --- a/src/test/resources/testng.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml new file mode 100644 index 00000000..26cc3ddd --- /dev/null +++ b/weixin-java-common/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + me.chanjar + weixin-java-parent + 1.0.3-SNAPSHOT + + + weixin-java-common + WeiXin Java Tools - Common + 微信公众号、企业号Java SDK Common + + + + junit + junit + test + + + org.testng + testng + 6.8.7 + test + + + org.mockito + mockito-all + 1.9.5 + test + + + com.google.inject + guice + 3.0 + test + + + org.eclipse.jetty + jetty-server + 9.3.0.M0 + test + + + org.eclipse.jetty + jetty-servlet + 9.3.0.M0 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + src/test/resources/testng.xml + + + + + + + diff --git a/src/main/java/me/chanjar/weixin/api/WxConsts.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java similarity index 74% rename from src/main/java/me/chanjar/weixin/api/WxConsts.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java index 534d63bd..084c8ee0 100644 --- a/src/main/java/me/chanjar/weixin/api/WxConsts.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.common.api; import java.util.HashMap; import java.util.Map; @@ -20,7 +20,7 @@ public class WxConsts { public static final String XML_TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; /////////////////////// - // 客服消息的消息类型 + // 主动发送消息的消息类型 /////////////////////// public static final String CUSTOM_MSG_TEXT = "text"; public static final String CUSTOM_MSG_IMAGE = "image"; @@ -28,6 +28,7 @@ public class WxConsts { public static final String CUSTOM_MSG_VIDEO = "video"; public static final String CUSTOM_MSG_MUSIC = "music"; public static final String CUSTOM_MSG_NEWS = "news"; + public static final String CUSTOM_MSG_FILE = "file"; /////////////////////// // 群发消息的消息类型 @@ -81,6 +82,12 @@ public class WxConsts { public static final String EVT_CLICK = "CLICK"; public static final String EVT_VIEW = "VIEW"; public static final String EVT_MASS_SEND_JOB_FINISH = "MASSSENDJOBFINISH"; + public static final String EVT_SCANCODE_PUSH = "scancode_push"; + public static final String EVT_SCANCODE_WAITMSG = "scancode_waitmsg"; + public static final String EVT_PIC_SYSPHOTO = "pic_sysphoto"; + public static final String EVT_PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; + public static final String EVT_PIC_WEIXIN = "pic_weixin"; + public static final String EVT_LOCATION_SELECT = "location_select"; /////////////////////// // 上传多媒体文件的类型 @@ -89,6 +96,7 @@ public class WxConsts { public static final String MEDIA_VOICE = "voice"; public static final String MEDIA_VIDEO = "video"; public static final String MEDIA_THUMB = "thumb"; + public static final String MEDIA_FILE = "file"; /////////////////////// // 文件类型 @@ -98,4 +106,25 @@ public class WxConsts { public static final String FILE_ARM = "arm"; public static final String FILE_MP4 = "mp4"; + + /////////////////////// + // 自定义菜单的按钮类型 + /////////////////////// + /** 点击推事件 */ + public static final String BUTTON_CLICK = "click"; + /** 跳转URL */ + public static final String BUTTON_VIEW = "view"; + /** 扫码推事件 */ + public static final String BUTTON_SCANCODE_PUSH = "scancode_push"; + /** 扫码推事件且弹出“消息接收中”提示框 */ + public static final String BUTTON_SCANCODE_WAITMSG = "scancode_waitmsg"; + /** 弹出系统拍照发图 */ + public static final String PIC_SYSPHOTO = "pic_sysphoto"; + /** 弹出拍照或者相册发图 */ + public static final String PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; + /** 弹出微信相册发图器 */ + public static final String PIC_WEIXIN = "pic_weixin"; + /** 弹出地理位置选择器 */ + public static final String LOCATION_SELECT = "location_select"; + } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxAccessToken.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxAccessToken.java new file mode 100644 index 00000000..2365daa2 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxAccessToken.java @@ -0,0 +1,31 @@ +package me.chanjar.weixin.common.bean; + +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +public class WxAccessToken { + + private String accessToken; + + private int expiresIn = -1; + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public int getExpiresIn() { + return expiresIn; + } + + public void setExpiresIn(int expiresIn) { + this.expiresIn = expiresIn; + } + + public static WxAccessToken fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxAccessToken.class); + } + +} diff --git a/src/main/java/me/chanjar/weixin/bean/WxMenu.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxMenu.java similarity index 66% rename from src/main/java/me/chanjar/weixin/bean/WxMenu.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxMenu.java index 06173aea..70110230 100644 --- a/src/main/java/me/chanjar/weixin/bean/WxMenu.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxMenu.java @@ -1,27 +1,27 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.common.bean; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; -import me.chanjar.weixin.util.json.WxGsonBuilder; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; /** - * 公众号菜单 - * @author chanjarster + * 企业号菜单 + * @author Daniel Qian * */ public class WxMenu { - private List button = new ArrayList(); + private List buttons = new ArrayList(); - public List getButton() { - return button; + public List getButtons() { + return buttons; } - public void setButton(List button) { - this.button = button; + public void setButtons(List buttons) { + this.buttons = buttons; } public String toJson() { @@ -43,7 +43,7 @@ public class WxMenu { private String key; private String url; - private List sub_button = new ArrayList(); + private List subButtons = new ArrayList(); public String getType() { return type; @@ -77,12 +77,12 @@ public class WxMenu { this.url = url; } - public List getSub_button() { - return sub_button; + public List getSubButtons() { + return subButtons; } - public void setSub_button(List sub_button) { - this.sub_button = sub_button; + public void setSubButtons(List subButtons) { + this.subButtons = subButtons; } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxError.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxError.java new file mode 100644 index 00000000..495ede81 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxError.java @@ -0,0 +1,53 @@ +package me.chanjar.weixin.common.bean.result; + +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +/** + * 微信错误码说明 + * http://mp.weixin.qq.com/wiki/index.php?title=全局返回码说明 + * @author Daniel Qian + * + */ +public class WxError { + + private int errorCode; + + private String errorMsg; + + private String json; + + public int getErrorCode() { + return errorCode; + } + + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMsg() { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) { + this.errorMsg = errorMsg; + } + + public String getJson() { + return json; + } + + public void setJson(String json) { + this.json = json; + } + + public static WxError fromJson(String json) { + WxError error = WxGsonBuilder.create().fromJson(json, WxError.class); + return error; + } + + @Override + public String toString() { + return "微信错误 errcode=" + errorCode + ", errmsg=" + errorMsg + "\njson:" + json; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java new file mode 100644 index 00000000..1695489a --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java @@ -0,0 +1,54 @@ +package me.chanjar.weixin.common.bean.result; + +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +public class WxMediaUploadResult { + + private String type; + private String mediaId; + private String thumbMediaId; + private long createdAt; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public long getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(long createdAt) { + this.createdAt = createdAt; + } + + public String getThumbMediaId() { + return thumbMediaId; + } + + public void setThumbMediaId(String thumbMediaId) { + this.thumbMediaId = thumbMediaId; + } + + public static WxMediaUploadResult fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMediaUploadResult.class); + } + + @Override + public String toString() { + return "WxUploadResult [type=" + type + ", media_id=" + mediaId + ", thumb_media_id=" + thumbMediaId + + ", created_at=" + createdAt + "]"; + } + +} diff --git a/src/main/java/me/chanjar/weixin/exception/WxErrorException.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/exception/WxErrorException.java similarity index 76% rename from src/main/java/me/chanjar/weixin/exception/WxErrorException.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/exception/WxErrorException.java index 311d00fb..d1dc569b 100644 --- a/src/main/java/me/chanjar/weixin/exception/WxErrorException.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/exception/WxErrorException.java @@ -1,6 +1,6 @@ -package me.chanjar.weixin.exception; +package me.chanjar.weixin.common.exception; -import me.chanjar.weixin.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxError; public class WxErrorException extends Exception { diff --git a/src/main/java/me/chanjar/weixin/util/crypto/ByteGroup.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/ByteGroup.java similarity index 65% rename from src/main/java/me/chanjar/weixin/util/crypto/ByteGroup.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/ByteGroup.java index b0bda3cb..de777dc9 100755 --- a/src/main/java/me/chanjar/weixin/util/crypto/ByteGroup.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/ByteGroup.java @@ -1,11 +1,11 @@ -package me.chanjar.weixin.util.crypto; +package me.chanjar.weixin.common.util.crypto; import java.util.ArrayList; -class ByteGroup { +public class ByteGroup { ArrayList byteContainer = new ArrayList(); - byte[] toBytes() { + public byte[] toBytes() { byte[] bytes = new byte[byteContainer.size()]; for (int i = 0; i < byteContainer.size(); i++) { bytes[i] = byteContainer.get(i); @@ -13,14 +13,14 @@ class ByteGroup { return bytes; } - ByteGroup addBytes(byte[] bytes) { + public ByteGroup addBytes(byte[] bytes) { for (byte b : bytes) { byteContainer.add(b); } return this; } - int size() { + public int size() { return byteContainer.size(); } } diff --git a/src/main/java/me/chanjar/weixin/util/crypto/PKCS7Encoder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/PKCS7Encoder.java similarity index 84% rename from src/main/java/me/chanjar/weixin/util/crypto/PKCS7Encoder.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/PKCS7Encoder.java index e02b509c..35771c47 100755 --- a/src/main/java/me/chanjar/weixin/util/crypto/PKCS7Encoder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/PKCS7Encoder.java @@ -6,7 +6,7 @@ // ------------------------------------------------------------------------ -package me.chanjar.weixin.util.crypto; +package me.chanjar.weixin.common.util.crypto; import java.nio.charset.Charset; import java.util.Arrays; @@ -14,7 +14,7 @@ import java.util.Arrays; /** * 提供基于PKCS7算法的加解 */ -class PKCS7Encoder { +public class PKCS7Encoder { private static final Charset CHARSET = Charset.forName("utf-8"); private static final int BLOCK_SIZE = 32; @@ -25,7 +25,7 @@ class PKCS7Encoder { * @param count 需要进行填充补位操作的明文字节个数 * @return 补齐用的字节数组 */ - static byte[] encode(int count) { + public static byte[] encode(int count) { // 计算需要填充的位数 int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE); if (amountToPad == 0) { @@ -46,7 +46,7 @@ class PKCS7Encoder { * @param decrypted 解密后的明文 * @return 删除补位字符后的明文 */ - static byte[] decode(byte[] decrypted) { + public static byte[] decode(byte[] decrypted) { int pad = (int) decrypted[decrypted.length - 1]; if (pad < 1 || pad > 32) { pad = 0; @@ -60,7 +60,7 @@ class PKCS7Encoder { * @param a 需要转化的数字 * @return 转化得到的字符 */ - static char chr(int a) { + public static char chr(int a) { byte target = (byte) (a & 0xFF); return (char) target; } diff --git a/src/main/java/me/chanjar/weixin/util/crypto/SHA1.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java similarity index 91% rename from src/main/java/me/chanjar/weixin/util/crypto/SHA1.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java index eec3c53b..cc233308 100644 --- a/src/main/java/me/chanjar/weixin/util/crypto/SHA1.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java @@ -1,11 +1,11 @@ -package me.chanjar.weixin.util.crypto; +package me.chanjar.weixin.common.util.crypto; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; /** - * Created by qianjia on 14/10/19. + * Created by Daniel Qian on 14/10/19. */ public class SHA1 { diff --git a/src/main/java/me/chanjar/weixin/util/crypto/WxCryptUtil.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java similarity index 86% rename from src/main/java/me/chanjar/weixin/util/crypto/WxCryptUtil.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java index 764d851b..363f0be0 100755 --- a/src/main/java/me/chanjar/weixin/util/crypto/WxCryptUtil.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java @@ -11,13 +11,12 @@ * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi */ -package me.chanjar.weixin.util.crypto; +package me.chanjar.weixin.common.util.crypto; -import java.io.StringReader; -import java.nio.charset.Charset; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.Random; +import org.apache.commons.codec.binary.Base64; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.InputSource; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; @@ -25,12 +24,11 @@ import javax.crypto.spec.SecretKeySpec; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; - -import me.chanjar.weixin.api.WxConfigStorage; -import org.apache.commons.codec.binary.Base64; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.InputSource; +import java.io.StringReader; +import java.nio.charset.Charset; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Random; public class WxCryptUtil { @@ -48,41 +46,24 @@ public class WxCryptUtil { } }; - private byte[] aesKey; - private String token; - private String appId; - - /** - * 构造函数 - * - * @param wxConfigStorage - */ - public WxCryptUtil(WxConfigStorage wxConfigStorage) { - /* - * @param token 公众平台上,开发者设置的token - * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey - * @param appId 公众平台appid - */ - String encodingAesKey = wxConfigStorage.getAesKey(); - String token = wxConfigStorage.getToken(); - String appId = wxConfigStorage.getAppId(); - - this.token = token; - this.appId = appId; - this.aesKey = Base64.decodeBase64(encodingAesKey + "="); + protected byte[] aesKey; + protected String token; + protected String appidOrCorpid; + public WxCryptUtil() { + super(); } /** * 构造函数 * - * @param token 公众平台上,开发者设置的token - * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey - * @param appId 公众平台appid + * @param token 公众平台上,开发者设置的token + * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey + * @param appidOrCorpid 公众平台appid/corpid */ - public WxCryptUtil(String token, String encodingAesKey, String appId) { + public WxCryptUtil(String token, String encodingAesKey, String appidOrCorpid) { this.token = token; - this.appId = appId; + this.appidOrCorpid = appidOrCorpid; this.aesKey = Base64.decodeBase64(encodingAesKey + "="); } @@ -125,7 +106,7 @@ public class WxCryptUtil { byte[] randomStringBytes = randomStr.getBytes(CHARSET); byte[] plainTextBytes = plainText.getBytes(CHARSET); byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(plainTextBytes.length); - byte[] appIdBytes = appId.getBytes(CHARSET); + byte[] appIdBytes = appidOrCorpid.getBytes(CHARSET); // randomStr + networkBytesOrder + text + appid byteCollector.addBytes(randomStringBytes); @@ -174,7 +155,7 @@ public class WxCryptUtil { * @return 解密后的原文 */ public String decrypt(String msgSignature, String timeStamp, String nonce, String encryptedXml) { - // 密钥,公众账号的app secret + // 密钥,公众账号的app corpSecret // 提取密文 String cipherText = extractEncryptPart(encryptedXml); @@ -199,7 +180,7 @@ public class WxCryptUtil { * @param cipherText 需要解密的密文 * @return 解密得到的明文 */ - protected String decrypt(String cipherText) { + public String decrypt(String cipherText) { byte[] original; try { // 设置解密模式为AES的CBC模式 @@ -235,7 +216,7 @@ public class WxCryptUtil { } // appid不相同的情况 - if (!from_appid.equals(appId)) { + if (!from_appid.equals(appidOrCorpid)) { throw new RuntimeException("AppID不正确"); } diff --git a/src/main/java/me/chanjar/weixin/util/fs/FileUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java similarity index 96% rename from src/main/java/me/chanjar/weixin/util/fs/FileUtils.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java index 1acc4561..d2ecc42a 100644 --- a/src/main/java/me/chanjar/weixin/util/fs/FileUtils.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.util.fs; +package me.chanjar.weixin.common.util.fs; import java.io.File; import java.io.FileOutputStream; diff --git a/src/main/java/me/chanjar/weixin/util/http/InputStreamResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamResponseHandler.java similarity index 95% rename from src/main/java/me/chanjar/weixin/util/http/InputStreamResponseHandler.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamResponseHandler.java index 8854e0f8..cf7f26cf 100644 --- a/src/main/java/me/chanjar/weixin/util/http/InputStreamResponseHandler.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamResponseHandler.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.util.http; +package me.chanjar.weixin.common.util.http; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/me/chanjar/weixin/util/http/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java similarity index 83% rename from src/main/java/me/chanjar/weixin/util/http/MediaDownloadRequestExecutor.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java index b62ad35f..caa8e03b 100644 --- a/src/main/java/me/chanjar/weixin/util/http/MediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java @@ -1,11 +1,11 @@ -package me.chanjar.weixin.util.http; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +package me.chanjar.weixin.common.util.http; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.client.ClientProtocolException; @@ -13,13 +13,15 @@ import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.entity.ContentType; -import me.chanjar.weixin.bean.result.WxError; -import me.chanjar.weixin.exception.WxErrorException; -import me.chanjar.weixin.util.fs.FileUtils; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File - * @author chanjarster + * @author Daniel Qian * */ public class MediaDownloadRequestExecutor implements RequestExecutor { diff --git a/src/main/java/me/chanjar/weixin/util/http/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java similarity index 82% rename from src/main/java/me/chanjar/weixin/util/http/MediaUploadRequestExecutor.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java index 6bad642a..62223722 100644 --- a/src/main/java/me/chanjar/weixin/util/http/MediaUploadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java @@ -1,8 +1,9 @@ -package me.chanjar.weixin.util.http; +package me.chanjar.weixin.common.util.http; import java.io.File; import java.io.IOException; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import org.apache.http.HttpEntity; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; @@ -10,13 +11,12 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.MultipartEntityBuilder; -import me.chanjar.weixin.bean.result.WxError; -import me.chanjar.weixin.bean.result.WxMediaUploadResult; -import me.chanjar.weixin.exception.WxErrorException; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; /** * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String - * @author chanjarster + * @author Daniel Qian * */ public class MediaUploadRequestExecutor implements RequestExecutor { @@ -35,7 +35,7 @@ public class MediaUploadRequestExecutor implements RequestExecutor 返回值类型 * @param 请求参数类型 diff --git a/src/main/java/me/chanjar/weixin/util/http/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java similarity index 82% rename from src/main/java/me/chanjar/weixin/util/http/SimpleGetRequestExecutor.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java index 62a81207..4d5ea024 100644 --- a/src/main/java/me/chanjar/weixin/util/http/SimpleGetRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.util.http; +package me.chanjar.weixin.common.util.http; import java.io.IOException; @@ -6,12 +6,12 @@ import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; -import me.chanjar.weixin.bean.result.WxError; -import me.chanjar.weixin.exception.WxErrorException; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; /** * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String - * @author chanjarster + * @author Daniel Qian * */ public class SimpleGetRequestExecutor implements RequestExecutor { @@ -28,7 +28,7 @@ public class SimpleGetRequestExecutor implements RequestExecutor CloseableHttpResponse response = httpclient.execute(httpGet); String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); WxError error = WxError.fromJson(responseContent); - if (error.getErrcode() != 0) { + if (error.getErrorCode() != 0) { throw new WxErrorException(error); } return responseContent; diff --git a/src/main/java/me/chanjar/weixin/util/http/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java similarity index 82% rename from src/main/java/me/chanjar/weixin/util/http/SimplePostRequestExecutor.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java index acd33086..8025d6dc 100644 --- a/src/main/java/me/chanjar/weixin/util/http/SimplePostRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java @@ -1,9 +1,9 @@ -package me.chanjar.weixin.util.http; +package me.chanjar.weixin.common.util.http; import java.io.IOException; -import me.chanjar.weixin.bean.result.WxError; -import me.chanjar.weixin.exception.WxErrorException; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; import org.apache.http.Consts; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; @@ -12,7 +12,7 @@ import org.apache.http.entity.StringEntity; /** * 简单的POST请求执行器,请求的参数是String, 返回的结果也是String - * @author chanjarster + * @author Daniel Qian * */ public class SimplePostRequestExecutor implements RequestExecutor { @@ -27,7 +27,7 @@ public class SimplePostRequestExecutor implements RequestExecutor { diff --git a/src/main/java/me/chanjar/weixin/util/json/GsonHelper.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonHelper.java similarity index 98% rename from src/main/java/me/chanjar/weixin/util/json/GsonHelper.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonHelper.java index 4dc16de0..614e28e2 100644 --- a/src/main/java/me/chanjar/weixin/util/json/GsonHelper.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonHelper.java @@ -6,7 +6,7 @@ * arose from modification of the original source, or other redistribution of this source * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. */ -package me.chanjar.weixin.util.json; +package me.chanjar.weixin.common.util.json; import com.google.gson.JsonElement; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxAccessTokenAdapter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxAccessTokenAdapter.java new file mode 100644 index 00000000..cfe4edb2 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxAccessTokenAdapter.java @@ -0,0 +1,36 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.common.util.json; + +import com.google.gson.*; +import me.chanjar.weixin.common.bean.WxAccessToken; + +import java.lang.reflect.Type; + +/** + * + * @author Daniel Qian + * + */ +public class WxAccessTokenAdapter implements JsonDeserializer { + + public WxAccessToken deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + WxAccessToken accessToken = new WxAccessToken(); + JsonObject accessTokenJsonObject = json.getAsJsonObject(); + + if (accessTokenJsonObject.get("access_token") != null && !accessTokenJsonObject.get("access_token").isJsonNull()) { + accessToken.setAccessToken(GsonHelper.getAsString(accessTokenJsonObject.get("access_token"))); + } + if (accessTokenJsonObject.get("expires_in") != null && !accessTokenJsonObject.get("expires_in").isJsonNull()) { + accessToken.setExpiresIn(GsonHelper.getAsPrimitiveInt(accessTokenJsonObject.get("expires_in"))); + } + return accessToken; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxErrorAdapter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxErrorAdapter.java new file mode 100644 index 00000000..74b9ded8 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxErrorAdapter.java @@ -0,0 +1,37 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.common.util.json; + +import com.google.gson.*; +import me.chanjar.weixin.common.bean.result.WxError; + +import java.lang.reflect.Type; + +/** + * + * @author Daniel Qian + * + */ +public class WxErrorAdapter implements JsonDeserializer { + + public WxError deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + WxError wxError = new WxError(); + JsonObject wxErrorJsonObject = json.getAsJsonObject(); + + if (wxErrorJsonObject.get("errcode") != null && !wxErrorJsonObject.get("errcode").isJsonNull()) { + wxError.setErrorCode(GsonHelper.getAsPrimitiveInt(wxErrorJsonObject.get("errcode"))); + } + if (wxErrorJsonObject.get("errmsg") != null && !wxErrorJsonObject.get("errmsg").isJsonNull()) { + wxError.setErrorMsg(GsonHelper.getAsString(wxErrorJsonObject.get("errmsg"))); + } + wxError.setJson(json.toString()); + return wxError; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxGsonBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxGsonBuilder.java new file mode 100644 index 00000000..7aa56965 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxGsonBuilder.java @@ -0,0 +1,26 @@ +package me.chanjar.weixin.common.util.json; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import me.chanjar.weixin.common.bean.WxMenu; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; + +public class WxGsonBuilder { + + public static final GsonBuilder INSTANCE = new GsonBuilder(); + + static { + INSTANCE.disableHtmlEscaping(); + INSTANCE.registerTypeAdapter(WxAccessToken.class, new WxAccessTokenAdapter()); + INSTANCE.registerTypeAdapter(WxError.class, new WxErrorAdapter()); + INSTANCE.registerTypeAdapter(WxMenu.class, new WxMenuGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMediaUploadResult.class, new WxMediaUploadResultAdapter()); + } + + public static Gson create() { + return INSTANCE.create(); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMediaUploadResultAdapter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMediaUploadResultAdapter.java new file mode 100644 index 00000000..35eb18b4 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMediaUploadResultAdapter.java @@ -0,0 +1,42 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.common.util.json; + +import com.google.gson.*; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; + +import java.lang.reflect.Type; + +/** + * + * @author Daniel Qian + * + */ +public class WxMediaUploadResultAdapter implements JsonDeserializer { + + public WxMediaUploadResult deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + WxMediaUploadResult uploadResult = new WxMediaUploadResult(); + JsonObject uploadResultJsonObject = json.getAsJsonObject(); + + if (uploadResultJsonObject.get("type") != null && !uploadResultJsonObject.get("type").isJsonNull()) { + uploadResult.setType(GsonHelper.getAsString(uploadResultJsonObject.get("type"))); + } + if (uploadResultJsonObject.get("media_id") != null && !uploadResultJsonObject.get("media_id").isJsonNull()) { + uploadResult.setMediaId(GsonHelper.getAsString(uploadResultJsonObject.get("media_id"))); + } + if (uploadResultJsonObject.get("thumb_media_id") != null && !uploadResultJsonObject.get("thumb_media_id").isJsonNull()) { + uploadResult.setThumbMediaId(GsonHelper.getAsString(uploadResultJsonObject.get("thumb_media_id"))); + } + if (uploadResultJsonObject.get("created_at") != null && !uploadResultJsonObject.get("created_at").isJsonNull()) { + uploadResult.setCreatedAt(GsonHelper.getAsPrimitiveLong(uploadResultJsonObject.get("created_at"))); + } + return uploadResult; + } + +} diff --git a/src/main/java/me/chanjar/weixin/util/json/WxMenuGsonAdapter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java similarity index 88% rename from src/main/java/me/chanjar/weixin/util/json/WxMenuGsonAdapter.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java index b267a760..6fc788d3 100644 --- a/src/main/java/me/chanjar/weixin/util/json/WxMenuGsonAdapter.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java @@ -6,11 +6,11 @@ * arose from modification of the original source, or other redistribution of this source * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. */ -package me.chanjar.weixin.util.json; +package me.chanjar.weixin.common.util.json; import java.lang.reflect.Type; -import me.chanjar.weixin.bean.WxMenu; +import me.chanjar.weixin.common.bean.WxMenu; import com.google.gson.JsonArray; import com.google.gson.JsonDeserializationContext; @@ -23,7 +23,7 @@ import com.google.gson.JsonSerializer; /** * - * @author qianjia + * @author Daniel Qian * */ public class WxMenuGsonAdapter implements JsonSerializer, JsonDeserializer { @@ -32,7 +32,7 @@ public class WxMenuGsonAdapter implements JsonSerializer, JsonDeserializ JsonObject json = new JsonObject(); JsonArray buttonArray = new JsonArray(); - for (WxMenu.WxMenuButton button : menu.getButton()) { + for (WxMenu.WxMenuButton button : menu.getButtons()) { JsonObject buttonJson = convertToJson(button); buttonArray.add(buttonJson); } @@ -47,9 +47,9 @@ public class WxMenuGsonAdapter implements JsonSerializer, JsonDeserializ buttonJson.addProperty("name", button.getName()); buttonJson.addProperty("key", button.getKey()); buttonJson.addProperty("url", button.getUrl()); - if (button.getSub_button() != null && button.getSub_button().size() > 0) { + if (button.getSubButtons() != null && button.getSubButtons().size() > 0) { JsonArray buttonArray = new JsonArray(); - for (WxMenu.WxMenuButton sub_button : button.getSub_button()) { + for (WxMenu.WxMenuButton sub_button : button.getSubButtons()) { buttonArray.add(convertToJson(sub_button)); } buttonJson.add("sub_button", buttonArray); @@ -69,14 +69,14 @@ public class WxMenuGsonAdapter implements JsonSerializer, JsonDeserializ for (int i = 0; i < buttonsJson.size(); i++) { JsonObject buttonJson = buttonsJson.get(i).getAsJsonObject(); WxMenu.WxMenuButton button = convertFromJson(buttonJson); - menu.getButton().add(button); + menu.getButtons().add(button); if (buttonJson.get("sub_button") == null || buttonJson.get("sub_button").isJsonNull()) { continue; } JsonArray sub_buttonsJson = buttonJson.get("sub_button").getAsJsonArray(); for (int j = 0; j < sub_buttonsJson.size(); j++) { JsonObject sub_buttonJson = sub_buttonsJson.get(j).getAsJsonObject(); - button.getSub_button().add(convertFromJson(sub_buttonJson)); + button.getSubButtons().add(convertFromJson(sub_buttonJson)); } } return menu; diff --git a/src/main/java/me/chanjar/weixin/util/xml/AdapterCDATA.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/AdapterCDATA.java similarity index 87% rename from src/main/java/me/chanjar/weixin/util/xml/AdapterCDATA.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/AdapterCDATA.java index edcceed8..c38c2795 100644 --- a/src/main/java/me/chanjar/weixin/util/xml/AdapterCDATA.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/AdapterCDATA.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.util.xml; +package me.chanjar.weixin.common.util.xml; import javax.xml.bind.annotation.adapters.XmlAdapter; @@ -6,7 +6,7 @@ import javax.xml.bind.annotation.adapters.XmlAdapter; * * http://stackoverflow.com/questions/14193944/jaxb-marshalling-unmarshalling-with-cdata * - * @author chanjarster + * @author Daniel Qian * */ public class AdapterCDATA extends XmlAdapter { diff --git a/src/main/java/me/chanjar/weixin/util/xml/MediaIdMarshaller.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/MediaIdMarshaller.java similarity index 85% rename from src/main/java/me/chanjar/weixin/util/xml/MediaIdMarshaller.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/MediaIdMarshaller.java index 39225136..10e6a3aa 100644 --- a/src/main/java/me/chanjar/weixin/util/xml/MediaIdMarshaller.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/MediaIdMarshaller.java @@ -1,9 +1,9 @@ -package me.chanjar.weixin.util.xml; +package me.chanjar.weixin.common.util.xml; import javax.xml.bind.annotation.adapters.XmlAdapter; /** - * @author chanjarster + * @author Daniel Qian */ public class MediaIdMarshaller extends XmlAdapter { diff --git a/src/test/java/me/chanjar/weixin/bean/WxAccessTokenTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxAccessTokenTest.java similarity index 58% rename from src/test/java/me/chanjar/weixin/bean/WxAccessTokenTest.java rename to weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxAccessTokenTest.java index 8f123b7c..d236c631 100644 --- a/src/test/java/me/chanjar/weixin/bean/WxAccessTokenTest.java +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxAccessTokenTest.java @@ -1,6 +1,5 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.common.bean; -import me.chanjar.weixin.bean.WxAccessToken; import org.testng.Assert; import org.testng.annotations.Test; @@ -11,8 +10,8 @@ public class WxAccessTokenTest { String json = "{\"access_token\":\"ACCESS_TOKEN\",\"expires_in\":7200}"; WxAccessToken wxError = WxAccessToken.fromJson(json); - Assert.assertEquals(wxError.getAccess_token(), "ACCESS_TOKEN"); - Assert.assertTrue(wxError.getExpires_in() == 7200); + Assert.assertEquals(wxError.getAccessToken(), "ACCESS_TOKEN"); + Assert.assertTrue(wxError.getExpiresIn() == 7200); } diff --git a/src/test/java/me/chanjar/weixin/bean/WxErrorTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxErrorTest.java similarity index 58% rename from src/test/java/me/chanjar/weixin/bean/WxErrorTest.java rename to weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxErrorTest.java index e3a8e5f7..51e9dab3 100644 --- a/src/test/java/me/chanjar/weixin/bean/WxErrorTest.java +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxErrorTest.java @@ -1,10 +1,9 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.common.bean; +import me.chanjar.weixin.common.bean.result.WxError; import org.testng.Assert; import org.testng.annotations.Test; -import me.chanjar.weixin.bean.result.WxError; - @Test public class WxErrorTest { @@ -12,8 +11,8 @@ public class WxErrorTest { String json = "{ \"errcode\": 40003, \"errmsg\": \"invalid openid\" }"; WxError wxError = WxError.fromJson(json); - Assert.assertTrue(wxError.getErrcode() == 40003); - Assert.assertEquals(wxError.getErrmsg(), "invalid openid"); + Assert.assertTrue(wxError.getErrorCode() == 40003); + Assert.assertEquals(wxError.getErrorMsg(), "invalid openid"); } @@ -21,8 +20,8 @@ public class WxErrorTest { String json = "{ \"errcode\": 40003, \"errmsg\": \"invalid openid\", \"media_id\": \"12323423dsfafsf232f\" }"; WxError wxError = WxError.fromJson(json); - Assert.assertTrue(wxError.getErrcode() == 40003); - Assert.assertEquals(wxError.getErrmsg(), "invalid openid"); + Assert.assertTrue(wxError.getErrorCode() == 40003); + Assert.assertEquals(wxError.getErrorMsg(), "invalid openid"); } @@ -30,8 +29,8 @@ public class WxErrorTest { String json = "{\"access_token\":\"ACCESS_TOKEN\",\"expires_in\":7200}"; WxError wxError = WxError.fromJson(json); - Assert.assertTrue(wxError.getErrcode() == 0); - Assert.assertEquals(wxError.getErrmsg(), null); + Assert.assertTrue(wxError.getErrorCode() == 0); + Assert.assertEquals(wxError.getErrorMsg(), null); } diff --git a/src/test/java/me/chanjar/weixin/bean/WxMenuTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxMenuTest.java similarity index 87% rename from src/test/java/me/chanjar/weixin/bean/WxMenuTest.java rename to weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxMenuTest.java index c9a0ceb9..015889d7 100644 --- a/src/test/java/me/chanjar/weixin/bean/WxMenuTest.java +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxMenuTest.java @@ -1,19 +1,17 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.common.bean; -import me.chanjar.weixin.bean.WxMenu; +import me.chanjar.weixin.common.bean.WxMenu.WxMenuButton; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import me.chanjar.weixin.bean.WxMenu.WxMenuButton; - @Test public class WxMenuTest { @Test(dataProvider="wxReturnMenu") public void testFromJson(String json) { WxMenu menu = WxMenu.fromJson(json); - Assert.assertEquals(menu.getButton().size(), 3); + Assert.assertEquals(menu.getButtons().size(), 3); } @Test(dataProvider="wxPushMenu") @@ -32,9 +30,9 @@ public class WxMenuTest { WxMenuButton button3 = new WxMenuButton(); button3.setName("菜单"); - menu.getButton().add(button1); - menu.getButton().add(button2); - menu.getButton().add(button3); + menu.getButtons().add(button1); + menu.getButtons().add(button2); + menu.getButtons().add(button3); WxMenuButton button31 = new WxMenuButton(); button31.setType("view"); @@ -51,9 +49,9 @@ public class WxMenuTest { button33.setName("赞一下我们"); button33.setKey("V1001_GOOD"); - button3.getSub_button().add(button31); - button3.getSub_button().add(button32); - button3.getSub_button().add(button33); + button3.getSubButtons().add(button31); + button3.getSubButtons().add(button32); + button3.getSubButtons().add(button33); Assert.assertEquals(menu.toJson(), json); } diff --git a/src/test/java/me/chanjar/weixin/util/crypto/WxCryptUtilTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/WxCryptUtilTest.java similarity index 94% rename from src/test/java/me/chanjar/weixin/util/crypto/WxCryptUtilTest.java rename to weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/WxCryptUtilTest.java index 0c61d3d0..15b08c26 100755 --- a/src/test/java/me/chanjar/weixin/util/crypto/WxCryptUtilTest.java +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/WxCryptUtilTest.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.util.crypto; +package me.chanjar.weixin.common.util.crypto; import org.testng.annotations.Test; import org.w3c.dom.Document; @@ -13,7 +13,8 @@ import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.io.StringReader; -import static org.testng.Assert.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; @Test public class WxCryptUtilTest { @@ -50,7 +51,7 @@ public class WxCryptUtilTest { String messageText = String.format(xmlFormat, cipherText); - // 第三方收到公众号平台发送的消息 + // 第三方收到企业号平台发送的消息 String plainMessage = pc.decrypt(cipherText); System.out.println(plainMessage); diff --git a/weixin-java-common/src/test/resources/testng.xml b/weixin-java-common/src/test/resources/testng.xml new file mode 100644 index 00000000..f0058b53 --- /dev/null +++ b/weixin-java-common/src/test/resources/testng.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/LICENSE b/weixin-java-cp/LICENSE similarity index 100% rename from LICENSE rename to weixin-java-cp/LICENSE diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml new file mode 100644 index 00000000..9c40e02d --- /dev/null +++ b/weixin-java-cp/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + + me.chanjar + weixin-java-parent + 1.0.3-SNAPSHOT + + + weixin-java-cp + WeiXin Java Tools - CP + 微信企业号Java SDK + + + + me.chanjar + weixin-java-common + ${project.version} + + + junit + junit + test + + + org.testng + testng + 6.8.7 + test + + + org.mockito + mockito-all + 1.9.5 + test + + + com.google.inject + guice + 3.0 + test + + + org.eclipse.jetty + jetty-server + 9.3.0.M0 + test + + + org.eclipse.jetty + jetty-servlet + 9.3.0.M0 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + src/test/resources/testng.xml + + + + + + + diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java new file mode 100644 index 00000000..d61b0035 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java @@ -0,0 +1,30 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.bean.WxAccessToken; + +/** + * 微信客户端配置存储 + * @author Daniel Qian + * + */ +public interface WxCpConfigStorage { + + public void updateAccessToken(WxAccessToken accessToken); + + public void updateAccessToken(String accessToken, int expiresIn); + + public String getAccessToken(); + + public String getCorpId(); + + public String getCorpSecret(); + + public String getAgentId(); + + public String getToken(); + + public String getAesKey(); + + public int getExpiresIn(); + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java new file mode 100644 index 00000000..26d15f4b --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java @@ -0,0 +1,98 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.bean.WxAccessToken; + +/** + * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 + * @author Daniel Qian + * + */ +public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { + + protected String corpId; + protected String corpSecret; + + protected String token; + protected String accessToken; + protected String aesKey; + protected String agentId; + protected int expiresIn; + + public void updateAccessToken(WxAccessToken accessToken) { + updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + } + + public void updateAccessToken(String accessToken, int expiresIn) { + this.accessToken = accessToken; + this.expiresIn = expiresIn; + } + + public String getAccessToken() { + return this.accessToken; + } + + public String getCorpId() { + return this.corpId; + } + + public String getCorpSecret() { + return this.corpSecret; + } + + public String getToken() { + return this.token; + } + + public int getExpiresIn() { + return this.expiresIn; + } + + public void setCorpId(String corpId) { + this.corpId = corpId; + } + + public void setCorpSecret(String corpSecret) { + this.corpSecret = corpSecret; + } + + public void setToken(String token) { + this.token = token; + } + + public String getAesKey() { + return aesKey; + } + + public void setAesKey(String aesKey) { + this.aesKey = aesKey; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public void setExpiresIn(int expiresIn) { + this.expiresIn = expiresIn; + } + + public String getAgentId() { + return agentId; + } + + public void setAgentId(String agentId) { + this.agentId = agentId; + } + + @Override + public String toString() { + return "WxInMemoryCpConfigStorage{" + + "appidOrCorpid='" + corpId + '\'' + + ", corpSecret='" + corpSecret + '\'' + + ", token='" + token + '\'' + + ", accessToken='" + accessToken + '\'' + + ", aesKey='" + aesKey + '\'' + + ", agentId='" + agentId + '\'' + + ", expiresIn=" + expiresIn + + '}'; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageHandler.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageHandler.java new file mode 100644 index 00000000..b82dddeb --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageHandler.java @@ -0,0 +1,23 @@ +package me.chanjar.weixin.cp.api; + +import java.util.Map; + +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; + +/** + * 处理微信推送消息的处理器接口 + * @author Daniel Qian + * + */ +public interface WxCpMessageHandler { + + /** + * + * @param wxMessage + * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @return xml格式的消息,如果在异步规则里处理的话,可以返回null + */ + public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context); + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageInterceptor.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageInterceptor.java new file mode 100644 index 00000000..7a09dacd --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageInterceptor.java @@ -0,0 +1,22 @@ +package me.chanjar.weixin.cp.api; + +import java.util.Map; + +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; + +/** + * 微信消息拦截器,可以用来做验证 + * @author Daniel Qian + * + */ +public interface WxCpMessageInterceptor { + + /** + * 拦截微信消息 + * @param wxMessage + * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @return true代表OK,false代表不OK + */ + public boolean intercept(WxCpXmlMessage wxMessage, Map context); + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java new file mode 100644 index 00000000..333fca9a --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java @@ -0,0 +1,307 @@ +package me.chanjar.weixin.cp.api; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.regex.Pattern; + +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; + +/** + *
+ * 微信消息路由器,通过代码化的配置,把来自微信的消息交给handler处理
+ *
+ * 说明:
+ * 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理
+ * 2. 默认情况下消息只会被处理一次,除非使用 {@link Rule#next()}
+ * 3. 规则的结束必须用{@link Rule#end()}或者{@link Rule#next()},否则不会生效
+ *
+ * 使用方法:
+ * WxCpMessageRouter router = new WxCpMessageRouter();
+ * router
+ *   .rule()
+ *       .msgType("MSG_TYPE").event("EVENT").eventKey("EVENT_KEY").content("CONTENT")
+ *       .interceptor(interceptor, ...).handler(handler, ...)
+ *   .end()
+ *   .rule()
+ *       // 另外一个匹配规则
+ *   .end()
+ * ;
+ *
+ * // 将WxXmlMessage交给消息路由器
+ * router.route(message);
+ *
+ * 
+ * @author Daniel Qian + * + */ +public class WxCpMessageRouter { + + private final List rules = new ArrayList(); + + private final ExecutorService es = Executors.newCachedThreadPool(); + + /** + * 开始一个新的Route规则 + * @return + */ + public Rule rule() { + return new Rule(this); + } + + /** + * 处理微信消息 + * @param wxMessage + */ + public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) { + final List matchRules = new ArrayList(); + // 收集匹配的规则 + for (final Rule rule : rules) { + if (rule.test(wxMessage)) { + matchRules.add(rule); + } + } + + if (matchRules.size() == 0) { + return null; + } + + if (matchRules.get(0).async) { + // 只要第一个是异步的,那就异步执行 + // 在另一个线程里执行 + es.submit(new Runnable() { + public void run() { + for (final Rule rule : matchRules) { + rule.service(wxMessage); + if (!rule.reEnter) { + break; + } + } + } + }); + return null; + } + + WxCpXmlOutMessage res = null; + for (final Rule rule : matchRules) { + // 返回最后一个匹配规则的结果 + res = rule.service(wxMessage); + if (!rule.reEnter) { + break; + } + } + return res; + } + + public static class Rule { + + private final WxCpMessageRouter routerBuilder; + + private boolean async = true; + + private String msgType; + + private String event; + + private String eventKey; + + private String content; + + private String rContent; + + private boolean reEnter = false; + + private Integer agentId; + + private List handlers = new ArrayList(); + + private List interceptors = new ArrayList(); + + protected Rule(WxCpMessageRouter routerBuilder) { + this.routerBuilder = routerBuilder; + } + + /** + * 设置是否异步执行,默认是true + * @param async + * @return + */ + public Rule async(boolean async) { + this.async = async; + return this; + } + + /** + * 如果agentId匹配 + * @param agentId + * @return + */ + public Rule agentId(Integer agentId) { + this.agentId = agentId; + return this; + } + + /** + * 如果msgType等于某值 + * @param msgType + * @return + */ + public Rule msgType(String msgType) { + this.msgType = msgType; + return this; + } + + /** + * 如果event等于某值 + * @param event + * @return + */ + public Rule event(String event) { + this.event = event; + return this; + } + + /** + * 如果eventKey等于某值 + * @param eventKey + * @return + */ + public Rule eventKey(String eventKey) { + this.eventKey = eventKey; + return this; + } + + /** + * 如果content等于某值 + * @param content + * @return + */ + public Rule content(String content) { + this.content = content; + return this; + } + + /** + * 如果content匹配该正则表达式 + * @param regex + * @return + */ + public Rule rContent(String regex) { + this.rContent = regex; + return this; + } + + /** + * 设置微信消息拦截器 + * @param interceptor + * @return + */ + public Rule interceptor(WxCpMessageInterceptor interceptor) { + return interceptor(interceptor, (WxCpMessageInterceptor[]) null); + } + + /** + * 设置微信消息拦截器 + * @param interceptor + * @param otherInterceptors + * @return + */ + public Rule interceptor(WxCpMessageInterceptor interceptor, WxCpMessageInterceptor... otherInterceptors) { + this.interceptors.add(interceptor); + if (otherInterceptors != null && otherInterceptors.length > 0) { + for (WxCpMessageInterceptor i : otherInterceptors) { + this.interceptors.add(i); + } + } + return this; + } + + /** + * 设置微信消息处理器 + * @param handler + * @return + */ + public Rule handler(WxCpMessageHandler handler) { + return handler(handler, (WxCpMessageHandler[]) null); + } + + /** + * 设置微信消息处理器 + * @param handler + * @param otherHandlers + * @return + */ + public Rule handler(WxCpMessageHandler handler, WxCpMessageHandler... otherHandlers) { + this.handlers.add(handler); + if (otherHandlers != null && otherHandlers.length > 0) { + for (WxCpMessageHandler i : otherHandlers) { + this.handlers.add(i); + } + } + return this; + } + + /** + * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 + * @return + */ + public WxCpMessageRouter end() { + this.routerBuilder.rules.add(this); + return this.routerBuilder; + } + + /** + * 规则结束,但是消息还会进入其他规则 + * @return + */ + public WxCpMessageRouter next() { + this.reEnter = true; + return end(); + } + + protected boolean test(WxCpXmlMessage wxMessage) { + return + (this.agentId == null || this.agentId.equals(wxMessage.getAgentId())) + && + (this.msgType == null || this.msgType.equals(wxMessage.getMsgType())) + && + (this.event == null || this.event.equals(wxMessage.getEvent())) + && + (this.eventKey == null || this.eventKey.equals(wxMessage.getEventKey())) + && + (this.content == null || this.content.equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) + && + (this.rContent == null || Pattern.matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) + ; + } + + /** + * 处理微信推送过来的消息 + * @param wxMessage + * @return true 代表继续执行别的router,false 代表停止执行别的router + */ + protected WxCpXmlOutMessage service(WxCpXmlMessage wxMessage) { + Map context = new HashMap(); + // 如果拦截器不通过 + for (WxCpMessageInterceptor interceptor : this.interceptors) { + if (!interceptor.intercept(wxMessage, context)) { + return null; + } + } + + // 交给handler处理 + WxCpXmlOutMessage res = null; + for (WxCpMessageHandler handler : this.handlers) { + // 返回最后handler的结果 + res = handler.handle(wxMessage, context); + } + return res; + } + + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java new file mode 100644 index 00000000..900a47f7 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -0,0 +1,290 @@ +package me.chanjar.weixin.cp.api; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import me.chanjar.weixin.common.bean.WxMenu; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.cp.bean.*; +import me.chanjar.weixin.cp.bean.WxCpDepart; +import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.common.exception.WxErrorException; + +/** + * 微信API的Service + */ +public interface WxCpService { + + /** + *
+   * 验证推送过来的消息的正确性
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=验证消息真实性
+   * 
+ * + * @param msgSignature + * @param timestamp + * @param nonce + * @param data 微信传输过来的数据,有可能是echoStr,有可能是xml消息 + * @return + */ + public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data); + + /** + *
+   *   用在二次验证的时候
+   *   企业在员工验证成功后,调用本方法告诉企业号平台该员工关注成功。
+   * 
+ * + * @param userId + */ + public void userAuthenticated(String userId) throws WxErrorException; + + /** + *
+   * 获取access_token,本方法线程安全
+   * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限
+   * 另:本service的所有方法都会在access_token过期是调用此方法
+   * 程序员在非必要情况下尽量不要主动调用此方法
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token
+   * 
+ * + * @throws me.chanjar.weixin.common.exception.WxErrorException + */ + public void accessTokenRefresh() throws WxErrorException; + + /** + *
+   * 上传多媒体文件
+   * 上传的多媒体文件有格式和大小限制,如下:
+   *   图片(image): 1M,支持JPG格式
+   *   语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式
+   *   视频(video):10MB,支持MP4格式
+   *   缩略图(thumb):64KB,支持JPG格式
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
+   * 
+ * + * @param mediaType 媒体类型, 请看{@link WxCpConsts} + * @param fileType 文件类型,请看{@link WxCpConsts} + * @param inputStream 输入流 + * @throws WxErrorException + */ + public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) + throws WxErrorException, IOException; + + /** + * @param mediaType + * @param file + * @throws WxErrorException + * @see #mediaUpload(String, String, InputStream) + */ + public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException; + + /** + *
+   * 下载多媒体文件
+   * 根据微信文档,视频文件下载不了,会返回null
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
+   * 
+ * + * @return 保存到本地的临时文件 + * @throws WxErrorException + * @params media_id + */ + public File mediaDownload(String media_id) throws WxErrorException; + + /** + *
+   * 发送消息
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=发送消息
+   * 
+ * + * @param message + * @throws WxErrorException + */ + public void messageSend(WxCpMessage message) throws WxErrorException; + + /** + *
+   * 自定义菜单创建接口
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
+   * 
+ * + * @param menu + * @throws WxErrorException + */ + public void menuCreate(WxMenu menu) throws WxErrorException; + + /** + *
+   * 自定义菜单删除接口
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
+   * 
+ * + * @throws WxErrorException + */ + public void menuDelete() throws WxErrorException; + + /** + *
+   * 自定义菜单查询接口
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
+   * 
+ * + * @return + * @throws WxErrorException + */ + public WxMenu menuGet() throws WxErrorException; + + /** + *
+   * 部门管理接口 - 创建部门
+   * 最多支持创建500个部门
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
+   * 
+ * + * @param depart 部门 + * @return 部门id + * @throws WxErrorException + */ + public Integer departCreate(WxCpDepart depart) throws WxErrorException; + + /** + *
+   * 部门管理接口 - 查询所有部门
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
+   * 
+ * + * @return + * @throws WxErrorException + */ + public List departGet() throws WxErrorException; + + /** + *
+   * 部门管理接口 - 修改部门名
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
+   * 如果id为0(未部门),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
+   * 
+ * + * @param group 要更新的group,group的id,name必须设置 + * @throws WxErrorException + */ + public void departUpdate(WxCpDepart group) throws WxErrorException; + + /** + *
+   * 部门管理接口 - 删除部门
+   * 
+ * + * @param departId + * @throws WxErrorException + */ + public void departDelete(Integer departId) throws WxErrorException; + + /** + * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98 + * + * @param departId 必填。部门id + * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 + * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 + * @return + * @throws WxErrorException + */ + public List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + + /** + * 新建用户 + * + * @param user + * @throws WxErrorException + */ + public void userCreate(WxCpUser user) throws WxErrorException; + + /** + * 更新用户 + * + * @param user + * @throws WxErrorException + */ + public void userUpdate(WxCpUser user) throws WxErrorException; + + /** + * 删除用户 + * + * @param userid + * @throws WxErrorException + */ + public void userDelete(String userid) throws WxErrorException; + + /** + * 获取用户 + * + * @param userid + * @return + * @throws WxErrorException + */ + public WxCpUser userGet(String userid) throws WxErrorException; + + /** + * 创建标签 + * + * @param tagName + * @return + */ + public String tagCreate(String tagName) throws WxErrorException; + + /** + * 更新标签 + * + * @param tagId + * @param tagName + */ + public void tagUpdate(String tagId, String tagName) throws WxErrorException; + + /** + * 删除标签 + * + * @param tagId + */ + public void tagDelete(String tagId) throws WxErrorException; + + /** + * 获得标签列表 + * + * @return + */ + public List tagGet() throws WxErrorException; + + /** + * 获取标签成员 + * + * @param tagId + * @return + */ + public List tagGetUsers(String tagId) throws WxErrorException; + + /** + * 增加标签成员 + * + * @param tagId + * @param userIds + */ + public void tagAddUsers(String tagId, List userIds) throws WxErrorException; + + /** + * 移除标签成员 + * + * @param tagId + * @param userIds + */ + public void tagRemoveUsers(String tagId, List userIds) throws WxErrorException; + + /** + * 注入 {@link WxCpConfigStorage} 的实现 + * + * @param wxConfigProvider + */ + public void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider); +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java new file mode 100644 index 00000000..4d9b2af3 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java @@ -0,0 +1,378 @@ +package me.chanjar.weixin.cp.api; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.WxMenu; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.cp.bean.*; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.crypto.SHA1; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; + +import me.chanjar.weixin.cp.bean.WxCpDepart; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; + +import com.google.gson.JsonElement; +import com.google.gson.internal.Streams; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; + +public class WxCpServiceImpl implements WxCpService { + + /** + * 全局的是否正在刷新Access Token的flag + * true: 正在刷新 + * false: 没有刷新 + */ + protected static final AtomicBoolean GLOBAL_ACCESS_TOKEN_REFRESH_FLAG = new AtomicBoolean(false); + + protected static final CloseableHttpClient httpclient = HttpClients.createDefault(); + + protected WxCpConfigStorage wxCpConfigStorage; + + protected final ThreadLocal retryTimes = new ThreadLocal(); + + public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data) { + try { + return SHA1.gen(wxCpConfigStorage.getToken(), timestamp, nonce, data).equals(msgSignature); + } catch (Exception e) { + return false; + } + } + + public void userAuthenticated(String userId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid=" + userId; + execute(new SimpleGetRequestExecutor(), url, null); + } + + public void accessTokenRefresh() throws WxErrorException { + if (!GLOBAL_ACCESS_TOKEN_REFRESH_FLAG.getAndSet(true)) { + try { + String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" + + "&corpid=" + wxCpConfigStorage.getCorpId() + + "&corpsecret=" + wxCpConfigStorage.getCorpSecret(); + try { + HttpGet httpGet = new HttpGet(url); + CloseableHttpResponse response = httpclient.execute(httpGet); + String resultContent = new BasicResponseHandler().handleResponse(response); + WxError error = WxError.fromJson(resultContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + wxCpConfigStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + } catch (ClientProtocolException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } finally { + GLOBAL_ACCESS_TOKEN_REFRESH_FLAG.set(false); + } + } else { + // 每隔100ms检查一下是否刷新完毕了 + while (GLOBAL_ACCESS_TOKEN_REFRESH_FLAG.get()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + // 刷新完毕了,就没他什么事儿了 + } + } + + public void messageSend(WxCpMessage message) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send"; + execute(new SimplePostRequestExecutor(), url, message.toJson()); + } + + public void menuCreate(WxMenu menu) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=" + wxCpConfigStorage.getAgentId(); + execute(new SimplePostRequestExecutor(), url, menu.toJson()); + } + + public void menuDelete() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=" + wxCpConfigStorage.getAgentId(); + execute(new SimpleGetRequestExecutor(), url, null); + } + + public WxMenu menuGet() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=" + wxCpConfigStorage.getAgentId(); + try { + String resultContent = execute(new SimpleGetRequestExecutor(), url, null); + return WxMenu.fromJson(resultContent); + } catch (WxErrorException e) { + // 46003 不存在的菜单数据 + if (e.getError().getErrorCode() == 46003) { + return null; + } + throw e; + } + } + + public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) + throws WxErrorException, IOException { + return mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); + } + + public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; + return execute(new MediaUploadRequestExecutor(), url, file); + } + + public File mediaDownload(String media_id) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; + return execute(new MediaDownloadRequestExecutor(), url, "media_id=" + media_id); + } + + + public Integer departCreate(WxCpDepart depart) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create"; + String responseContent = execute( + new SimplePostRequestExecutor(), + url, + depart.toJson()); + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); + return GsonHelper.getAsInteger(tmpJsonElement.getAsJsonObject().get("id")); + } + + public void departUpdate(WxCpDepart group) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/update"; + execute(new SimplePostRequestExecutor(), url, group.toJson()); + } + + public void departDelete(Integer departId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId; + execute(new SimpleGetRequestExecutor(), url, null); + } + + public List departGet() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"; + String responseContent = execute(new SimpleGetRequestExecutor(), url, null); + /* + * 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} } + * 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] } + */ + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("department"), + new TypeToken>() { }.getType() + ); + } + + @Override + public void userCreate(WxCpUser user) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/create"; + execute(new SimplePostRequestExecutor(), url, user.toJson()); + } + + @Override + public void userUpdate(WxCpUser user) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/update"; + execute(new SimplePostRequestExecutor(), url, user.toJson()); + } + + @Override + public void userDelete(String userid) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=" + userid; + execute(new SimpleGetRequestExecutor(), url, null); + } + + @Override + public WxCpUser userGet(String userid) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?userid=" + userid; + String responseContent = execute(new SimpleGetRequestExecutor(), url, null); + return WxCpUser.fromJson(responseContent); + } + + @Override + public List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId; + String params = ""; + if (fetchChild != null) { + params += "&fetch_child=" + (fetchChild ? "1" : "0"); + } + if (status != null) { + params += "&status=" + status; + } else { + params += "&status=0"; + } + + String responseContent = execute(new SimpleGetRequestExecutor(), url, params); + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("userlist"), + new TypeToken>() { }.getType() + ); + } + + @Override + public String tagCreate(String tagName) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/create"; + JsonObject o = new JsonObject(); + o.addProperty("tagname", tagName); + String responseContent = execute(new SimplePostRequestExecutor(), url, o.toString()); + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); + return tmpJsonElement.getAsJsonObject().get("tagid").getAsString(); + } + + @Override + public void tagUpdate(String tagId, String tagName) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/update"; + JsonObject o = new JsonObject(); + o.addProperty("tagid", tagId); + o.addProperty("tagname", tagName); + execute(new SimplePostRequestExecutor(), url, o.toString()); + } + + @Override + public void tagDelete(String tagId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=" + tagId; + execute(new SimpleGetRequestExecutor(), url, null); + } + + @Override + public List tagGet() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list"; + String responseContent = execute(new SimpleGetRequestExecutor(), url, null); + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("taglist"), + new TypeToken>() { }.getType() + ); + } + + @Override + public List tagGetUsers(String tagId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId; + String responseContent = execute(new SimpleGetRequestExecutor(), url, null); + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("userlist"), + new TypeToken>() { }.getType() + ); + } + + @Override + public void tagAddUsers(String tagId, List userIds) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("tagid", tagId); + JsonArray jsonArray = new JsonArray(); + for (String userId : userIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("userlist", jsonArray); + execute(new SimplePostRequestExecutor(), url, jsonObject.toString()); + } + + @Override + public void tagRemoveUsers(String tagId, List userIds) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("tagid", tagId); + JsonArray jsonArray = new JsonArray(); + for (String userId : userIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("userlist", jsonArray); + execute(new SimplePostRequestExecutor(), url, jsonObject.toString()); + } + + /** + * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 + * + * @param executor + * @param uri + * @param data + * @return + * @throws WxErrorException + */ + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + if (StringUtils.isBlank(wxCpConfigStorage.getAccessToken())) { + accessTokenRefresh(); + } + String accessToken = wxCpConfigStorage.getAccessToken(); + + String uriWithAccessToken = uri; + uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; + + try { + return executor.execute(uriWithAccessToken, data); + } catch (WxErrorException e) { + WxError error = e.getError(); + /* + * 发生以下情况时尝试刷新access_token + * 40001 获取access_token时AppSecret错误,或者access_token无效 + * 42001 access_token超时 + */ + if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { + accessTokenRefresh(); + return execute(executor, uri, data); + } + /** + * -1 系统繁忙, 1000ms后重试 + */ + if (error.getErrorCode() == -1) { + if (retryTimes.get() == null) { + retryTimes.set(0); + } + if (retryTimes.get() > 4) { + retryTimes.set(0); + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + int sleepMillis = 1000 * (1 << retryTimes.get()); + try { + System.out.println("微信系统繁忙," + sleepMillis + "ms后重试"); + Thread.sleep(sleepMillis); + retryTimes.set(retryTimes.get() + 1); + return execute(executor, uri, data); + } catch (InterruptedException e1) { + throw new RuntimeException(e1); + } + } + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return null; + } catch (ClientProtocolException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider) { + this.wxCpConfigStorage = wxConfigProvider; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java new file mode 100644 index 00000000..975cd595 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java @@ -0,0 +1,66 @@ +package me.chanjar.weixin.cp.bean; + +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +/** + * 微信部门 + * + * @author Daniel Qian + */ +public class WxCpDepart { + + private Integer id; + private String name; + private Integer parentId; + private Integer order; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getParentId() { + return parentId; + } + + public void setParentId(Integer parentId) { + this.parentId = parentId; + } + + public Integer getOrder() { + return order; + } + + public void setOrder(Integer order) { + this.order = order; + } + + public static WxCpDepart fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpDepart.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + @Override + public String toString() { + return "WxCpDepart{" + + "id=" + id + + ", name='" + name + '\'' + + ", parentId=" + parentId + + ", order=" + order + + '}'; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java new file mode 100644 index 00000000..d700aa74 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java @@ -0,0 +1,215 @@ +package me.chanjar.weixin.cp.bean; + +import java.util.ArrayList; +import java.util.List; + +import me.chanjar.weixin.cp.bean.messagebuilder.*; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +/** + * 消息 + * @author Daniel Qian + * + */ +public class WxCpMessage { + + private String toUser; + private String toParty; + private String toTag; + private String agentId; + private String msgType; + private String content; + private String mediaId; + private String thumbMediaId; + private String title; + private String description; + private String musicUrl; + private String hqMusicUrl; + private List articles = new ArrayList(); + + public String getToUser() { + return toUser; + } + public void setToUser(String toUser) { + this.toUser = toUser; + } + + public String getToParty() { + return toParty; + } + + public void setToParty(String toParty) { + this.toParty = toParty; + } + + public String getToTag() { + return toTag; + } + + public void setToTag(String toTag) { + this.toTag = toTag; + } + + public String getAgentId() { + return agentId; + } + + public void setAgentId(String agentId) { + this.agentId = agentId; + } + + public String getMsgType() { + return msgType; + } + + /** + *
+   * 请使用
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#CUSTOM_MSG_TEXT}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#CUSTOM_MSG_IMAGE}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#CUSTOM_MSG_VOICE}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#CUSTOM_MSG_MUSIC}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#CUSTOM_MSG_VIDEO}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#CUSTOM_MSG_NEWS}
+   * 
+ * @param msgType + */ + public void setMsgType(String msgType) { + this.msgType = msgType; + } + public String getContent() { + return content; + } + public void setContent(String content) { + this.content = content; + } + public String getMediaId() { + return mediaId; + } + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + public String getThumbMediaId() { + return thumbMediaId; + } + public void setThumbMediaId(String thumbMediaId) { + this.thumbMediaId = thumbMediaId; + } + public String getTitle() { + return title; + } + public void setTitle(String title) { + this.title = title; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public String getMusicUrl() { + return musicUrl; + } + public void setMusicUrl(String musicUrl) { + this.musicUrl = musicUrl; + } + public String getHqMusicUrl() { + return hqMusicUrl; + } + public void setHqMusicUrl(String hqMusicUrl) { + this.hqMusicUrl = hqMusicUrl; + } + public List getArticles() { + return articles; + } + public void setArticles(List articles) { + this.articles = articles; + } + + public String toJson() { + return WxCpGsonBuilder.INSTANCE.create().toJson(this); + } + + public static class WxArticle { + + private String title; + private String description; + private String url; + private String picUrl; + + public String getTitle() { + return title; + } + public void setTitle(String title) { + this.title = title; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public String getUrl() { + return url; + } + public void setUrl(String url) { + this.url = url; + } + public String getPicUrl() { + return picUrl; + } + public void setPicUrl(String picUrl) { + this.picUrl = picUrl; + } + + } + + /** + * 获得文本消息builder + * @return + */ + public static TextBuilder TEXT() { + return new TextBuilder(); + } + + /** + * 获得图片消息builder + * @return + */ + public static ImageBuilder IMAGE() { + return new ImageBuilder(); + } + + /** + * 获得语音消息builder + * @return + */ + public static VoiceBuilder VOICE() { + return new VoiceBuilder(); + } + + /** + * 获得视频消息builder + * @return + */ + public static VideoBuilder VIDEO() { + return new VideoBuilder(); + } + + /** + * 获得图文消息builder + * @return + */ + public static NewsBuilder NEWS() { + return new NewsBuilder(); + } + + /** + * 获得文件消息builder + * @return + */ + public static FileBuilder FILE() { + return new FileBuilder(); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java new file mode 100644 index 00000000..a56e9c5c --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java @@ -0,0 +1,48 @@ +package me.chanjar.weixin.cp.bean; + +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +/** + * Created by Daniel Qian + */ +public class WxCpTag { + + private String id; + + private String name; + + public WxCpTag() { + super(); + } + + public WxCpTag(String id, String name) { + super(); + this.id = id; + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public static WxCpTag fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpTag.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java new file mode 100644 index 00000000..90125a5d --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java @@ -0,0 +1,142 @@ +package me.chanjar.weixin.cp.bean; + +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.util.ArrayList; +import java.util.List; + +/** + * 微信用户信息 + * + * @author Daniel Qian + */ +public class WxCpUser { + + private String userId; + private String name; + private Integer[] departIds; + private String position; + private String mobile; + private String gender; + private String tel; + private String email; + private String weiXinId; + private final List extAttrs = new ArrayList(); + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer[] getDepartIds() { + return departIds; + } + + public void setDepartIds(Integer[] departIds) { + this.departIds = departIds; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + public String getPosition() { + return position; + } + + public void setPosition(String position) { + this.position = position; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getTel() { + return tel; + } + + public void setTel(String tel) { + this.tel = tel; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getWeiXinId() { + return weiXinId; + } + + public void setWeiXinId(String weiXinId) { + this.weiXinId = weiXinId; + } + + public void addExtAttr(String name, String value) { + this.extAttrs.add(new Attr(name, value)); + } + + public List getExtAttrs() { + return extAttrs; + } + + public String toJson() { + return WxCpGsonBuilder.INSTANCE.create().toJson(this); + } + + public static WxCpUser fromJson(String json) { + return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpUser.class); + } + + public static class Attr { + + private String name; + private String value; + + public Attr(String name, String value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java new file mode 100644 index 00000000..82d2884c --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java @@ -0,0 +1,648 @@ +package me.chanjar.weixin.cp.bean; + +import me.chanjar.weixin.common.util.xml.AdapterCDATA; +import me.chanjar.weixin.cp.api.WxCpConfigStorage; +import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; +import me.chanjar.weixin.cp.util.xml.XmlTransformer; +import org.apache.commons.io.IOUtils; + +import javax.xml.bind.JAXBException; +import javax.xml.bind.annotation.*; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + *
+ * 微信推送过来的消息,也是同步回复给用户的消息,xml格式
+ * 相关字段的解释看微信开发者文档:
+ * http://mp.weixin.qq.com/wiki/index.php?title=接收普通消息
+ * http://mp.weixin.qq.com/wiki/index.php?title=接收事件推送
+ * http://mp.weixin.qq.com/wiki/index.php?title=接收语音识别结果
+ * 
+ * + * @author Daniel Qian + */ +@XmlRootElement(name = "xml") +@XmlAccessorType(XmlAccessType.FIELD) +public class WxCpXmlMessage { + + /////////////////////// + // 以下都是微信推送过来的消息的xml的element所对应的属性 + /////////////////////// + + @XmlElement(name="AgentID") + private Integer agentId; + + @XmlElement(name = "ToUserName") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String toUserName; + + @XmlElement(name = "FromUserName") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String fromUserName; + + @XmlElement(name = "CreateTime") + private Long createTime; + + @XmlElement(name = "MsgType") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String msgType; + + @XmlElement(name = "Content") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String content; + + @XmlElement(name = "MsgId") + private Long msgId; + + @XmlElement(name = "PicUrl") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String picUrl; + + @XmlElement(name = "MediaId") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String mediaId; + + @XmlElement(name = "Format") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String format; + + @XmlElement(name = "ThumbMediaId") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String thumbMediaId; + + @XmlElement(name = "Location_X") + private Double locationX; + + @XmlElement(name = "Location_Y") + private Double locationY; + + @XmlElement(name = "Scale") + private Double scale; + + @XmlElement(name = "Label") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String label; + + @XmlElement(name = "Title") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String title; + + @XmlElement(name = "Description") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String description; + + @XmlElement(name = "Url") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String url; + + @XmlElement(name = "Event") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String event; + + @XmlElement(name = "EventKey") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String eventKey; + + @XmlElement(name = "Ticket") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String ticket; + + @XmlElement(name = "Latitude") + private Double latitude; + + @XmlElement(name = "Longitude") + private Double longitude; + + @XmlElement(name = "Precision") + private Double precision; + + @XmlElement(name = "Recognition") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String recognition; + + /////////////////////////////////////// + // 群发消息返回的结果 + /////////////////////////////////////// + /** + * 群发的结果 + */ + @XmlElement(name = "Status") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String status; + /** + * group_id下粉丝数;或者openid_list中的粉丝数 + */ + @XmlElement(name = "TotalCount") + private Integer totalCount; + /** + * 过滤(过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超4条的过滤)后,准备发送的粉丝数,原则上,filterCount = sentCount + errorCount + */ + @XmlElement(name = "FilterCount") + private Integer filterCount; + /** + * 发送成功的粉丝数 + */ + @XmlElement(name = "SentCount") + private Integer sentCount; + /** + * 发送失败的粉丝数 + */ + @XmlElement(name = "ErrorCount") + private Integer errorCount; + + @XmlElement(name = "ScanCodeInfo") + private ScanCodeInfo scanCodeInfo = new ScanCodeInfo(); + + @XmlElement(name = "SendPicsInfo") + private SendPicsInfo sendPicsInfo = new SendPicsInfo(); + + @XmlElement(name = "SendLocationInfo") + private SendLocationInfo sendLocationInfo = new SendLocationInfo(); + + public Integer getAgentId() { + return agentId; + } + + public void setAgentId(Integer agentId) { + this.agentId = agentId; + } + + public String getToUserName() { + return toUserName; + } + + public void setToUserName(String toUserName) { + this.toUserName = toUserName; + } + + public Long getCreateTime() { + return createTime; + } + + public void setCreateTime(Long createTime) { + this.createTime = createTime; + } + + /** + *
+   * 当接受用户消息时,可能会获得以下值:
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#XML_MSG_TEXT}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#XML_MSG_IMAGE}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#XML_MSG_VOICE}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#XML_MSG_VIDEO}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#XML_MSG_LOCATION}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#XML_MSG_LINK}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#XML_MSG_EVENT}
+   * 
+ * + * @return + */ + public String getMsgType() { + return msgType; + } + + /** + *
+   * 当发送消息的时候使用:
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#XML_MSG_TEXT}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#XML_MSG_IMAGE}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#XML_MSG_VOICE}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#XML_MSG_VIDEO}
+   * {@link me.chanjar.weixin.cp.api.WxCpConsts#XML_MSG_NEWS}
+   * 
+ * + * @param msgType + */ + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public Long getMsgId() { + return msgId; + } + + public void setMsgId(Long msgId) { + this.msgId = msgId; + } + + public String getPicUrl() { + return picUrl; + } + + public void setPicUrl(String picUrl) { + this.picUrl = picUrl; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public String getThumbMediaId() { + return thumbMediaId; + } + + public void setThumbMediaId(String thumbMediaId) { + this.thumbMediaId = thumbMediaId; + } + + public Double getLocationX() { + return locationX; + } + + public void setLocationX(Double locationX) { + this.locationX = locationX; + } + + public Double getLocationY() { + return locationY; + } + + public void setLocationY(Double locationY) { + this.locationY = locationY; + } + + public Double getScale() { + return scale; + } + + public void setScale(Double scale) { + this.scale = scale; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getEvent() { + return event; + } + + public void setEvent(String event) { + this.event = event; + } + + public String getEventKey() { + return eventKey; + } + + public void setEventKey(String eventKey) { + this.eventKey = eventKey; + } + + public String getTicket() { + return ticket; + } + + public void setTicket(String ticket) { + this.ticket = ticket; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Double getPrecision() { + return precision; + } + + public void setPrecision(Double precision) { + this.precision = precision; + } + + public String getRecognition() { + return recognition; + } + + public void setRecognition(String recognition) { + this.recognition = recognition; + } + + public String getFromUserName() { + return fromUserName; + } + + public void setFromUserName(String fromUserName) { + this.fromUserName = fromUserName; + } + + protected static WxCpXmlMessage fromXml(String xml) { + try { + return XmlTransformer.fromXml(WxCpXmlMessage.class, xml); + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } + + protected static WxCpXmlMessage fromXml(InputStream is) { + try { + return XmlTransformer.fromXml(WxCpXmlMessage.class, is); + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } + + /** + * 从加密字符串转换 + * + * @param encryptedXml + * @param wxCpConfigStorage + * @param timestamp + * @param nonce + * @param msgSignature + * @return + */ + public static WxCpXmlMessage fromEncryptedXml( + String encryptedXml, + WxCpConfigStorage wxCpConfigStorage, + String timestamp, String nonce, String msgSignature) { + WxCpCryptUtil cryptUtil = new WxCpCryptUtil(wxCpConfigStorage); + String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml); + return fromXml(plainText); + } + + public static WxCpXmlMessage fromEncryptedXml( + InputStream is, + WxCpConfigStorage wxCpConfigStorage, + String timestamp, String nonce, String msgSignature) { + try { + return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxCpConfigStorage, timestamp, nonce, msgSignature); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Integer getTotalCount() { + return totalCount; + } + + public void setTotalCount(Integer totalCount) { + this.totalCount = totalCount; + } + + public Integer getFilterCount() { + return filterCount; + } + + public void setFilterCount(Integer filterCount) { + this.filterCount = filterCount; + } + + public Integer getSentCount() { + return sentCount; + } + + public void setSentCount(Integer sentCount) { + this.sentCount = sentCount; + } + + public Integer getErrorCount() { + return errorCount; + } + + public void setErrorCount(Integer errorCount) { + this.errorCount = errorCount; + } + + public WxCpXmlMessage.ScanCodeInfo getScanCodeInfo() { + return scanCodeInfo; + } + + public void setScanCodeInfo(WxCpXmlMessage.ScanCodeInfo scanCodeInfo) { + this.scanCodeInfo = scanCodeInfo; + } + + public WxCpXmlMessage.SendPicsInfo getSendPicsInfo() { + return sendPicsInfo; + } + + public void setSendPicsInfo(WxCpXmlMessage.SendPicsInfo sendPicsInfo) { + this.sendPicsInfo = sendPicsInfo; + } + + public WxCpXmlMessage.SendLocationInfo getSendLocationInfo() { + return sendLocationInfo; + } + + public void setSendLocationInfo(WxCpXmlMessage.SendLocationInfo sendLocationInfo) { + this.sendLocationInfo = sendLocationInfo; + } + + @XmlRootElement(name = "ScanCodeInfo") + @XmlAccessorType(XmlAccessType.FIELD) + public static class ScanCodeInfo { + + @XmlElement(name = "ScanType") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String scanType; + + @XmlElement(name = "ScanResult") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String scanResult; + + /** + * 扫描类型,一般是qrcode + * @return + */ + public String getScanType() { + + return scanType; + } + + public void setScanType(String scanType) { + this.scanType = scanType; + } + + /** + * 扫描结果,即二维码对应的字符串信息 + * @return + */ + public String getScanResult() { + return scanResult; + } + + public void setScanResult(String scanResult) { + this.scanResult = scanResult; + } + + } + + @XmlRootElement(name = "SendPicsInfo") + @XmlAccessorType(XmlAccessType.FIELD) + public static class SendPicsInfo { + + @XmlElement(name = "Count") + private Long count; + + @XmlElementWrapper(name="PicList") + @XmlElement(name = "item") + protected final List picList = new ArrayList(); + + public Long getCount() { + return count; + } + + public void setCount(Long count) { + this.count = count; + } + + public List getPicList() { + return picList; + } + + @XmlRootElement(name = "item") + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "WxXmlMessage.SendPicsInfo.Item") + public static class Item { + + @XmlElement(name = "PicMd5Sum") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String PicMd5Sum; + + public String getPicMd5Sum() { + return PicMd5Sum; + } + + public void setPicMd5Sum(String picMd5Sum) { + PicMd5Sum = picMd5Sum; + } + } + } + + @XmlRootElement(name = "SendLocationInfo") + @XmlAccessorType(XmlAccessType.FIELD) + public static class SendLocationInfo { + + @XmlElement(name = "Location_X") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String locationX; + + @XmlElement(name = "Location_Y") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String locationY; + + @XmlElement(name = "Scale") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String scale; + + @XmlElement(name = "Label") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String label; + + @XmlElement(name = "Poiname") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String poiname; + + public String getLocationX() { + return locationX; + } + + public void setLocationX(String locationX) { + this.locationX = locationX; + } + + public String getLocationY() { + return locationY; + } + + public void setLocationY(String locationY) { + this.locationY = locationY; + } + + public String getScale() { + return scale; + } + + public void setScale(String scale) { + this.scale = scale; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getPoiname() { + return poiname; + } + + public void setPoiname(String poiname) { + this.poiname = poiname; + } + } + +} diff --git a/src/main/java/me/chanjar/weixin/bean/WxXmlOutImageMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessage.java similarity index 58% rename from src/main/java/me/chanjar/weixin/bean/WxXmlOutImageMessage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessage.java index 8cd7da8f..29efa04f 100644 --- a/src/main/java/me/chanjar/weixin/bean/WxXmlOutImageMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessage.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.cp.bean; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @@ -6,27 +6,27 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.util.xml.MediaIdMarshaller; +import me.chanjar.weixin.cp.api.WxCpConsts; +import me.chanjar.weixin.common.util.xml.MediaIdMarshaller; @XmlRootElement(name = "xml") @XmlAccessorType(XmlAccessType.FIELD) -public class WxXmlOutImageMessage extends WxXmlOutMessage { +public class WxCpXmlOutImageMessage extends WxCpXmlOutMessage { @XmlElement(name="Image") @XmlJavaTypeAdapter(MediaIdMarshaller.class) - private String MediaId; + private String mediaId; - public WxXmlOutImageMessage() { - this.MsgType = WxConsts.XML_MSG_IMAGE; + public WxCpXmlOutImageMessage() { + this.msgType = WxCpConsts.XML_MSG_IMAGE; } public String getMediaId() { - return MediaId; + return mediaId; } public void setMediaId(String mediaId) { - MediaId = mediaId; + this.mediaId = mediaId; } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java new file mode 100644 index 00000000..1ccacb00 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java @@ -0,0 +1,124 @@ +package me.chanjar.weixin.cp.bean; + +import me.chanjar.weixin.common.util.xml.AdapterCDATA; +import me.chanjar.weixin.cp.api.WxCpConfigStorage; +import me.chanjar.weixin.cp.bean.outxmlbuilder.*; +import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; +import me.chanjar.weixin.cp.util.xml.XmlTransformer; + +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; + +@XmlRootElement(name = "xml") +@XmlAccessorType(XmlAccessType.FIELD) +public class WxCpXmlOutMessage { + + @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) { + this.toUserName = toUserName; + } + + public String getFromUserName() { + return fromUserName; + } + + public void setFromUserName(String fromUserName) { + this.fromUserName = fromUserName; + } + + public Long getCreateTime() { + return createTime; + } + + public void setCreateTime(Long createTime) { + this.createTime = createTime; + } + + public String getMsgType() { + return msgType; + } + + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + protected String toXml() { + try { + return XmlTransformer.toXml((Class)this.getClass(), this); + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } + + /** + * 转换成加密的xml格式 + * @return + */ + public String toEncryptedXml(WxCpConfigStorage wxCpConfigStorage) { + String plainXml = toXml(); + WxCpCryptUtil pc = new WxCpCryptUtil(wxCpConfigStorage); + return pc.encrypt(plainXml); + } + + /** + * 获得文本消息builder + * @return + */ + public static TextBuilder TEXT() { + return new TextBuilder(); + } + + /** + * 获得图片消息builder + * @return + */ + public static ImageBuilder IMAGE() { + return new ImageBuilder(); + } + + /** + * 获得语音消息builder + * @return + */ + public static VoiceBuilder VOICE() { + return new VoiceBuilder(); + } + + /** + * 获得视频消息builder + * @return + */ + public static VideoBuilder VIDEO() { + return new VideoBuilder(); + } + + /** + * 获得图文消息builder + * @return + */ + public static NewsBuilder NEWS() { + return new NewsBuilder(); + } +} diff --git a/src/main/java/me/chanjar/weixin/bean/WxXmlOutMewsMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMewsMessage.java similarity index 76% rename from src/main/java/me/chanjar/weixin/bean/WxXmlOutMewsMessage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMewsMessage.java index 5d97600c..24264f24 100644 --- a/src/main/java/me/chanjar/weixin/bean/WxXmlOutMewsMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMewsMessage.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.cp.bean; import java.util.ArrayList; import java.util.List; @@ -10,35 +10,35 @@ import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.util.xml.AdapterCDATA; +import me.chanjar.weixin.cp.api.WxCpConsts; +import me.chanjar.weixin.common.util.xml.AdapterCDATA; @XmlRootElement(name = "xml") @XmlAccessorType(XmlAccessType.FIELD) -public class WxXmlOutMewsMessage extends WxXmlOutMessage { +public class WxCpXmlOutMewsMessage extends WxCpXmlOutMessage { @XmlElement(name = "ArticleCount") - protected int ArticleCount; + protected int articleCount; @XmlElementWrapper(name="Articles") - @XmlElement(name = "Item") - protected final List Articles = new ArrayList(); + @XmlElement(name = "item") + protected final List articles = new ArrayList(); - public WxXmlOutMewsMessage() { - this.MsgType = WxConsts.XML_MSG_NEWS; + public WxCpXmlOutMewsMessage() { + this.msgType = WxCpConsts.XML_MSG_NEWS; } public int getArticleCount() { - return ArticleCount; + return articleCount; } public void addArticle(Item item) { - this.Articles.add(item); - this.ArticleCount = this.Articles.size(); + this.articles.add(item); + this.articleCount = this.articles.size(); } public List getArticles() { - return Articles; + return articles; } diff --git a/src/main/java/me/chanjar/weixin/bean/WxXmlOutTextMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessage.java similarity index 58% rename from src/main/java/me/chanjar/weixin/bean/WxXmlOutTextMessage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessage.java index b140be2c..25a447fc 100644 --- a/src/main/java/me/chanjar/weixin/bean/WxXmlOutTextMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessage.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.cp.bean; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @@ -6,27 +6,27 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.util.xml.AdapterCDATA; +import me.chanjar.weixin.cp.api.WxCpConsts; +import me.chanjar.weixin.common.util.xml.AdapterCDATA; @XmlRootElement(name = "xml") @XmlAccessorType(XmlAccessType.FIELD) -public class WxXmlOutTextMessage extends WxXmlOutMessage { +public class WxCpXmlOutTextMessage extends WxCpXmlOutMessage { @XmlElement(name="Content") @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Content; + private String content; - public WxXmlOutTextMessage() { - this.MsgType = WxConsts.XML_MSG_TEXT; + public WxCpXmlOutTextMessage() { + this.msgType = WxCpConsts.XML_MSG_TEXT; } public String getContent() { - return Content; + return content; } public void setContent(String content) { - Content = content; + this.content = content; } diff --git a/src/main/java/me/chanjar/weixin/bean/WxXmlOutVideoMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessage.java similarity index 74% rename from src/main/java/me/chanjar/weixin/bean/WxXmlOutVideoMessage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessage.java index 26a8d6bd..896a71a5 100644 --- a/src/main/java/me/chanjar/weixin/bean/WxXmlOutVideoMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessage.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.cp.bean; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @@ -6,18 +6,18 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.util.xml.AdapterCDATA; +import me.chanjar.weixin.cp.api.WxCpConsts; +import me.chanjar.weixin.common.util.xml.AdapterCDATA; @XmlRootElement(name = "xml") @XmlAccessorType(XmlAccessType.FIELD) -public class WxXmlOutVideoMessage extends WxXmlOutMessage { +public class WxCpXmlOutVideoMessage extends WxCpXmlOutMessage { @XmlElement(name = "Video") protected final Video video = new Video(); - public WxXmlOutVideoMessage() { - this.MsgType = WxConsts.XML_MSG_VIDEO; + public WxCpXmlOutVideoMessage() { + this.msgType = WxCpConsts.XML_MSG_VIDEO; } public String getMediaId() { @@ -51,38 +51,38 @@ public class WxXmlOutVideoMessage extends WxXmlOutMessage { @XmlElement(name = "MediaId") @XmlJavaTypeAdapter(AdapterCDATA.class) - private String MediaId; + private String mediaId; @XmlElement(name = "Title") @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Title; + private String title; @XmlElement(name = "Description") @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Description; + private String description; public String getMediaId() { - return MediaId; + return mediaId; } public void setMediaId(String mediaId) { - MediaId = mediaId; + this.mediaId = mediaId; } public String getTitle() { - return Title; + return title; } public void setTitle(String title) { - Title = title; + this.title = title; } public String getDescription() { - return Description; + return description; } public void setDescription(String description) { - Description = description; + this.description = description; } } diff --git a/src/main/java/me/chanjar/weixin/bean/WxXmlOutVoiceMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessage.java similarity index 58% rename from src/main/java/me/chanjar/weixin/bean/WxXmlOutVoiceMessage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessage.java index df428c0b..b943aee9 100644 --- a/src/main/java/me/chanjar/weixin/bean/WxXmlOutVoiceMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessage.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.cp.bean; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @@ -6,27 +6,27 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.util.xml.MediaIdMarshaller; +import me.chanjar.weixin.cp.api.WxCpConsts; +import me.chanjar.weixin.common.util.xml.MediaIdMarshaller; @XmlRootElement(name = "xml") @XmlAccessorType(XmlAccessType.FIELD) -public class WxXmlOutVoiceMessage extends WxXmlOutMessage { +public class WxCpXmlOutVoiceMessage extends WxCpXmlOutMessage { @XmlElement(name="Voice") @XmlJavaTypeAdapter(MediaIdMarshaller.class) - private String MediaId; + private String mediaId; - public WxXmlOutVoiceMessage() { - this.MsgType = WxConsts.XML_MSG_VOICE; + public WxCpXmlOutVoiceMessage() { + this.msgType = WxCpConsts.XML_MSG_VOICE; } public String getMediaId() { - return MediaId; + return mediaId; } public void setMediaId(String mediaId) { - MediaId = mediaId; + this.mediaId = mediaId; } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java new file mode 100644 index 00000000..f52f274c --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java @@ -0,0 +1,42 @@ +package me.chanjar.weixin.cp.bean.messagebuilder; + +import me.chanjar.weixin.cp.bean.WxCpMessage; + +public class BaseBuilder { + protected String msgType; + protected String agentId; + protected String toUser; + protected String toParty; + protected String toTag; + + public T agentId(String agentId) { + this.agentId = agentId; + return (T) this; + } + + public T toUser(String toUser) { + this.toUser = toUser; + return (T) this; + } + + public T toParty(String toParty) { + this.toParty = toParty; + return (T) this; + } + + public T toTag(String toTag) { + this.toTag = toTag; + return (T) this; + } + + public WxCpMessage build() { + WxCpMessage m = new WxCpMessage(); + m.setAgentId(this.agentId); + m.setMsgType(this.msgType); + m.setToUser(this.toUser); + m.setToParty(this.toParty); + m.setToTag(this.toTag); + return m; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/FileBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/FileBuilder.java new file mode 100644 index 00000000..ac15b5ee --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/FileBuilder.java @@ -0,0 +1,31 @@ +package me.chanjar.weixin.cp.bean.messagebuilder; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.cp.bean.WxCpMessage; + +/** + * 获得消息builder + *
+ * 用法: WxCustomMessage m = WxCustomMessage.FILE().mediaId(...).toUser(...).build();
+ * 
+ * @author Daniel Qian + * + */ +public final class FileBuilder extends BaseBuilder { + private String mediaId; + + public FileBuilder() { + this.msgType = WxConsts.CUSTOM_MSG_FILE; + } + + public FileBuilder mediaId(String media_id) { + this.mediaId = media_id; + return this; + } + + public WxCpMessage build() { + WxCpMessage m = super.build(); + m.setMediaId(this.mediaId); + return m; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/ImageBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/ImageBuilder.java new file mode 100644 index 00000000..5098708a --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/ImageBuilder.java @@ -0,0 +1,31 @@ +package me.chanjar.weixin.cp.bean.messagebuilder; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.cp.bean.WxCpMessage; + +/** + * 获得消息builder + *
+ * 用法: WxCustomMessage m = WxCustomMessage.IMAGE().mediaId(...).toUser(...).build();
+ * 
+ * @author Daniel Qian + * + */ +public final class ImageBuilder extends BaseBuilder { + private String mediaId; + + public ImageBuilder() { + this.msgType = WxConsts.CUSTOM_MSG_IMAGE; + } + + public ImageBuilder mediaId(String media_id) { + this.mediaId = media_id; + return this; + } + + public WxCpMessage build() { + WxCpMessage m = super.build(); + m.setMediaId(this.mediaId); + return m; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/NewsBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/NewsBuilder.java new file mode 100644 index 00000000..0711b6f5 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/NewsBuilder.java @@ -0,0 +1,36 @@ +package me.chanjar.weixin.cp.bean.messagebuilder; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.cp.bean.WxCpMessage; + +import java.util.ArrayList; +import java.util.List; + +/** + * 图文消息builder + *
+ * 用法:
+ * WxCustomMessage m = WxCustomMessage.NEWS().addArticle(article).toUser(...).build();
+ * 
+ * @author Daniel Qian + * + */ +public final class NewsBuilder extends BaseBuilder { + + private List articles = new ArrayList(); + + public NewsBuilder() { + this.msgType = WxConsts.CUSTOM_MSG_NEWS; + } + + public NewsBuilder addArticle(WxCpMessage.WxArticle article) { + this.articles.add(article); + return this; + } + + public WxCpMessage build() { + WxCpMessage m = super.build(); + m.setArticles(this.articles); + return m; + } +} diff --git a/src/main/java/me/chanjar/weixin/bean/custombuilder/TextBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/TextBuilder.java similarity index 56% rename from src/main/java/me/chanjar/weixin/bean/custombuilder/TextBuilder.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/TextBuilder.java index 61b029ef..44a75b8f 100644 --- a/src/main/java/me/chanjar/weixin/bean/custombuilder/TextBuilder.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/TextBuilder.java @@ -1,21 +1,21 @@ -package me.chanjar.weixin.bean.custombuilder; +package me.chanjar.weixin.cp.bean.messagebuilder; -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.bean.WxCustomMessage; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.cp.bean.WxCpMessage; /** * 文本消息builder *
- * 用法: WxCustomMessage m = WxCustomMessage.TEXT().content(...).touser(...).build();
+ * 用法: WxCustomMessage m = WxCustomMessage.TEXT().content(...).toUser(...).build();
  * 
- * @author chanjarster + * @author Daniel Qian * */ public final class TextBuilder extends BaseBuilder { private String content; public TextBuilder() { - this.msgtype = WxConsts.CUSTOM_MSG_TEXT; + this.msgType = WxConsts.CUSTOM_MSG_TEXT; } public TextBuilder content(String content) { @@ -23,8 +23,8 @@ public final class TextBuilder extends BaseBuilder { return this; } - public WxCustomMessage build() { - WxCustomMessage m = super.build(); + public WxCpMessage build() { + WxCpMessage m = super.build(); m.setContent(this.content); return m; } diff --git a/src/main/java/me/chanjar/weixin/bean/custombuilder/VideoBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/VideoBuilder.java similarity index 53% rename from src/main/java/me/chanjar/weixin/bean/custombuilder/VideoBuilder.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/VideoBuilder.java index fd718dfa..32990fa3 100644 --- a/src/main/java/me/chanjar/weixin/bean/custombuilder/VideoBuilder.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/VideoBuilder.java @@ -1,34 +1,34 @@ -package me.chanjar.weixin.bean.custombuilder; +package me.chanjar.weixin.cp.bean.messagebuilder; -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.bean.WxCustomMessage; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.cp.bean.WxCpMessage; /** * 视频消息builder *
  * 用法: WxCustomMessage m = WxCustomMessage.VOICE()
- *                              .media_id(...)
+ *                              .mediaId(...)
  *                              .title(...)
- *                              .thumb_media_id(..)
+ *                              .thumbMediaId(..)
  *                              .description(..)
- *                              .touser(...)
+ *                              .toUser(...)
  *                              .build();
  * 
- * @author chanjarster + * @author Daniel Qian * */ public final class VideoBuilder extends BaseBuilder { - private String media_id; + private String mediaId; private String title; private String description; - private String thumb_media_id; + private String thumbMediaId; public VideoBuilder() { - this.msgtype = WxConsts.CUSTOM_MSG_VIDEO; + this.msgType = WxConsts.CUSTOM_MSG_VIDEO; } - public VideoBuilder mediaId(String media_id) { - this.media_id = media_id; + public VideoBuilder mediaId(String mediaId) { + this.mediaId = mediaId; return this; } @@ -43,16 +43,16 @@ public final class VideoBuilder extends BaseBuilder { } public VideoBuilder thumbMediaId(String thumb_media_id) { - this.thumb_media_id = thumb_media_id; + this.thumbMediaId = thumb_media_id; return this; } - public WxCustomMessage build() { - WxCustomMessage m = super.build(); - m.setMedia_id(this.media_id); + public WxCpMessage build() { + WxCpMessage m = super.build(); + m.setMediaId(this.mediaId); m.setTitle(title); m.setDescription(description); - m.setThumb_media_id(thumb_media_id); + m.setThumbMediaId(thumbMediaId); return m; } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/VoiceBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/VoiceBuilder.java new file mode 100644 index 00000000..99914fcd --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/VoiceBuilder.java @@ -0,0 +1,31 @@ +package me.chanjar.weixin.cp.bean.messagebuilder; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.cp.bean.WxCpMessage; + +/** + * 语音消息builder + *
+ * 用法: WxCustomMessage m = WxCustomMessage.VOICE().mediaId(...).toUser(...).build();
+ * 
+ * @author Daniel Qian + * + */ +public final class VoiceBuilder extends BaseBuilder { + private String mediaId; + + public VoiceBuilder() { + this.msgType = WxConsts.CUSTOM_MSG_VOICE; + } + + public VoiceBuilder mediaId(String media_id) { + this.mediaId = media_id; + return this; + } + + public WxCpMessage build() { + WxCpMessage m = super.build(); + m.setMediaId(this.mediaId); + return m; + } +} diff --git a/src/main/java/me/chanjar/weixin/bean/outxmlbuilder/BaseBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/BaseBuilder.java similarity index 72% rename from src/main/java/me/chanjar/weixin/bean/outxmlbuilder/BaseBuilder.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/BaseBuilder.java index 03d9985e..78ba1074 100644 --- a/src/main/java/me/chanjar/weixin/bean/outxmlbuilder/BaseBuilder.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/BaseBuilder.java @@ -1,7 +1,6 @@ -package me.chanjar.weixin.bean.outxmlbuilder; - -import me.chanjar.weixin.bean.WxXmlOutMessage; +package me.chanjar.weixin.cp.bean.outxmlbuilder; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; public abstract class BaseBuilder { @@ -9,7 +8,7 @@ public abstract class BaseBuilder { protected String fromUserName; - public BuilderType touser(String touser) { + public BuilderType toUser(String touser) { this.toUserName = touser; return (BuilderType) this; } @@ -21,7 +20,7 @@ public abstract class BaseBuilder { public abstract ValueType build(); - public void setCommon(WxXmlOutMessage m) { + public void setCommon(WxCpXmlOutMessage m) { m.setToUserName(this.toUserName); m.setFromUserName(this.fromUserName); m.setCreateTime(System.currentTimeMillis() / 1000l); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/ImageBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/ImageBuilder.java new file mode 100644 index 00000000..ac3b7fc9 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/ImageBuilder.java @@ -0,0 +1,25 @@ +package me.chanjar.weixin.cp.bean.outxmlbuilder; + +import me.chanjar.weixin.cp.bean.WxCpXmlOutImageMessage; + +/** + * 图片消息builder + * @author Daniel Qian + */ +public final class ImageBuilder extends BaseBuilder { + + private String mediaId; + + public ImageBuilder mediaId(String media_id) { + this.mediaId = media_id; + return this; + } + + public WxCpXmlOutImageMessage build() { + WxCpXmlOutImageMessage m = new WxCpXmlOutImageMessage(); + setCommon(m); + m.setMediaId(this.mediaId); + return m; + } + +} diff --git a/src/main/java/me/chanjar/weixin/bean/outxmlbuilder/NewsBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/NewsBuilder.java similarity index 57% rename from src/main/java/me/chanjar/weixin/bean/outxmlbuilder/NewsBuilder.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/NewsBuilder.java index 6168705b..1785f714 100644 --- a/src/main/java/me/chanjar/weixin/bean/outxmlbuilder/NewsBuilder.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/NewsBuilder.java @@ -1,16 +1,16 @@ -package me.chanjar.weixin.bean.outxmlbuilder; +package me.chanjar.weixin.cp.bean.outxmlbuilder; import java.util.ArrayList; import java.util.List; -import me.chanjar.weixin.bean.WxXmlOutMewsMessage; -import me.chanjar.weixin.bean.WxXmlOutMewsMessage.Item; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMewsMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMewsMessage.Item; /** * 图文消息builder - * @author chanjarster + * @author Daniel Qian */ -public final class NewsBuilder extends BaseBuilder { +public final class NewsBuilder extends BaseBuilder { protected final List articles = new ArrayList(); @@ -19,8 +19,8 @@ public final class NewsBuilder extends BaseBuilder { + private String content; + + public TextBuilder content(String content) { + this.content = content; + return this; + } + + public WxCpXmlOutTextMessage build() { + WxCpXmlOutTextMessage m = new WxCpXmlOutTextMessage(); + setCommon(m); + m.setContent(this.content); + return m; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/VideoBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/VideoBuilder.java new file mode 100644 index 00000000..1bb42ff2 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/VideoBuilder.java @@ -0,0 +1,38 @@ +package me.chanjar.weixin.cp.bean.outxmlbuilder; + +import me.chanjar.weixin.cp.bean.WxCpXmlOutVideoMessage; + +/** + * 视频消息builder + * @author Daniel Qian + * + */ +public final class VideoBuilder extends BaseBuilder { + + private String mediaId; + private String title; + private String description; + + public VideoBuilder title(String title) { + this.title = title; + return this; + } + public VideoBuilder description(String description) { + this.description = description; + return this; + } + public VideoBuilder mediaId(String mediaId) { + this.mediaId = mediaId; + return this; + } + + public WxCpXmlOutVideoMessage build() { + WxCpXmlOutVideoMessage m = new WxCpXmlOutVideoMessage(); + setCommon(m); + m.setTitle(title); + m.setDescription(description); + m.setMediaId(mediaId); + return m; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/VoiceBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/VoiceBuilder.java new file mode 100644 index 00000000..fb07525a --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/VoiceBuilder.java @@ -0,0 +1,25 @@ +package me.chanjar.weixin.cp.bean.outxmlbuilder; + +import me.chanjar.weixin.cp.bean.WxCpXmlOutVoiceMessage; + +/** + * 语音消息builder + * @author Daniel Qian + */ +public final class VoiceBuilder extends BaseBuilder { + + private String mediaId; + + public VoiceBuilder mediaId(String mediaId) { + this.mediaId = mediaId; + return this; + } + + public WxCpXmlOutVoiceMessage build() { + WxCpXmlOutVoiceMessage m = new WxCpXmlOutVoiceMessage(); + setCommon(m); + m.setMediaId(mediaId); + return m; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java new file mode 100755 index 00000000..d2d01c09 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java @@ -0,0 +1,43 @@ +/** + * 对公众平台发送给公众账号的消息加解密示例代码. + * + * @copyright Copyright (c) 1998-2014 Tencent Inc. + */ + +// ------------------------------------------------------------------------ + +/** + * 针对org.apache.commons.codec.binary.Base64, + * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) + * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi + */ +package me.chanjar.weixin.cp.util.crypto; + +import me.chanjar.weixin.common.util.crypto.WxCryptUtil; +import me.chanjar.weixin.cp.api.WxCpConfigStorage; +import org.apache.commons.codec.binary.Base64; + +public class WxCpCryptUtil extends WxCryptUtil { + + /** + * 构造函数 + * + * @param wxCpConfigStorage + */ + public WxCpCryptUtil(WxCpConfigStorage wxCpConfigStorage) { + /* + * @param token 公众平台上,开发者设置的token + * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey + * @param appidOrCorpid 公众平台appid + */ + String encodingAesKey = wxCpConfigStorage.getAesKey(); + String token = wxCpConfigStorage.getToken(); + String corpId = wxCpConfigStorage.getCorpId(); + + this.token = token; + this.appidOrCorpid = corpId; + this.aesKey = Base64.decodeBase64(encodingAesKey + "="); + } + + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java new file mode 100644 index 00000000..022333f8 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java @@ -0,0 +1,65 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.cp.util.json; + +import java.lang.reflect.Type; + +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.cp.bean.WxCpDepart; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +/** + * @author Daniel Qian + */ +public class WxCpDepartGsonAdapter implements JsonSerializer, JsonDeserializer { + + public JsonElement serialize(WxCpDepart group, Type typeOfSrc, JsonSerializationContext context) { + JsonObject json = new JsonObject(); + if (group.getId() != null) { + json.addProperty("id", group.getId()); + } + if (group.getName() != null) { + json.addProperty("name", group.getName()); + } + if (group.getParentId() != null) { + json.addProperty("parentid", group.getParentId()); + } + if (group.getOrder() != null) { + json.addProperty("order", String.valueOf(group.getOrder())); + } + return json; + } + + public WxCpDepart deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + WxCpDepart depart = new WxCpDepart(); + JsonObject departJson = json.getAsJsonObject(); + if (departJson.get("id") != null && !departJson.get("id").isJsonNull()) { + depart.setId(GsonHelper.getAsInteger(departJson.get("id"))); + } + if (departJson.get("name") != null && !departJson.get("name").isJsonNull()) { + depart.setName(GsonHelper.getAsString(departJson.get("name"))); + } + if (departJson.get("order") != null && !departJson.get("order").isJsonNull()) { + depart.setOrder(GsonHelper.getAsInteger(departJson.get("order"))); + } + if (departJson.get("parentid") != null && !departJson.get("parentid").isJsonNull()) { + depart.setParentId(GsonHelper.getAsInteger(departJson.get("parentid"))); + } + return depart; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java new file mode 100644 index 00000000..3a8b739b --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java @@ -0,0 +1,28 @@ +package me.chanjar.weixin.cp.util.json; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.util.json.WxMediaUploadResultAdapter; +import me.chanjar.weixin.common.util.json.WxErrorAdapter; +import me.chanjar.weixin.cp.bean.*; + +public class WxCpGsonBuilder { + + public static final GsonBuilder INSTANCE = new GsonBuilder(); + + static { + INSTANCE.disableHtmlEscaping(); + INSTANCE.registerTypeAdapter(WxCpMessage.class, new WxCpMessageGsonAdapter()); + INSTANCE.registerTypeAdapter(WxCpDepart.class, new WxCpDepartGsonAdapter()); + INSTANCE.registerTypeAdapter(WxCpUser.class, new WxCpUserGsonAdapter()); + INSTANCE.registerTypeAdapter(WxError.class, new WxErrorAdapter()); + INSTANCE.registerTypeAdapter(WxCpTag.class, new WxCpTagGsonAdapter()); + } + + public static Gson create() { + return INSTANCE.create(); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMessageGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMessageGsonAdapter.java new file mode 100644 index 00000000..2864e51f --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMessageGsonAdapter.java @@ -0,0 +1,93 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.cp.util.json; + +import java.lang.reflect.Type; + +import me.chanjar.weixin.cp.api.WxCpConsts; +import me.chanjar.weixin.cp.bean.WxCpMessage; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import org.apache.commons.lang3.StringUtils; + +/** + * + * @author Daniel Qian + * + */ +public class WxCpMessageGsonAdapter implements JsonSerializer { + + public JsonElement serialize(WxCpMessage message, Type typeOfSrc, JsonSerializationContext context) { + JsonObject messageJson = new JsonObject(); + messageJson.addProperty("agentid", message.getAgentId()); + if (StringUtils.isNotBlank(message.getToUser())) { + messageJson.addProperty("touser", message.getToUser()); + } + messageJson.addProperty("msgtype", message.getMsgType()); + + if (StringUtils.isNotBlank(message.getToParty())) { + messageJson.addProperty("toparty", message.getToUser()); + } + if (StringUtils.isNotBlank(message.getToTag())) { + messageJson.addProperty("totag", message.getToUser()); + } + if (WxCpConsts.CUSTOM_MSG_TEXT.equals(message.getMsgType())) { + JsonObject text = new JsonObject(); + text.addProperty("content", message.getContent()); + messageJson.add("text", text); + } + + if (WxCpConsts.CUSTOM_MSG_IMAGE.equals(message.getMsgType())) { + JsonObject image = new JsonObject(); + image.addProperty("media_id", message.getMediaId()); + messageJson.add("image", image); + } + + if (WxCpConsts.CUSTOM_MSG_FILE.equals(message.getMsgType())) { + JsonObject image = new JsonObject(); + image.addProperty("media_id", message.getMediaId()); + messageJson.add("file", image); + } + + if (WxCpConsts.CUSTOM_MSG_VOICE.equals(message.getMsgType())) { + JsonObject voice = new JsonObject(); + voice.addProperty("media_id", message.getMediaId()); + messageJson.add("voice", voice); + } + + if (WxCpConsts.CUSTOM_MSG_VIDEO.equals(message.getMsgType())) { + JsonObject video = new JsonObject(); + video.addProperty("media_id", message.getMediaId()); + video.addProperty("thumb_media_id", message.getThumbMediaId()); + video.addProperty("title", message.getTitle()); + video.addProperty("description", message.getDescription()); + messageJson.add("video", video); + } + + if (WxCpConsts.CUSTOM_MSG_NEWS.equals(message.getMsgType())) { + JsonArray articleJsonArray = new JsonArray(); + for (WxCpMessage.WxArticle article : message.getArticles()) { + JsonObject articleJson = new JsonObject(); + articleJson.addProperty("title", article.getTitle()); + articleJson.addProperty("description", article.getDescription()); + articleJson.addProperty("url", article.getUrl()); + articleJson.addProperty("picurl", article.getPicUrl()); + articleJsonArray.add(articleJson); + } + messageJson.add("articles", articleJsonArray); + } + + return messageJson; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java new file mode 100644 index 00000000..776e8a44 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java @@ -0,0 +1,35 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.cp.util.json; + +import com.google.gson.*; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.cp.bean.WxCpTag; + +import java.lang.reflect.Type; + +/** + * @author Daniel Qian + */ +public class WxCpTagGsonAdapter implements JsonSerializer, JsonDeserializer { + + public JsonElement serialize(WxCpTag group, Type typeOfSrc, JsonSerializationContext context) { + JsonObject o = new JsonObject(); + o.addProperty("tagid", group.getId()); + o.addProperty("tagname", group.getName()); + return o; + } + + public WxCpTag deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + JsonObject jsonObject = json.getAsJsonObject(); + return new WxCpTag(GsonHelper.getString(jsonObject, "tagid"), GsonHelper.getString(jsonObject, "name")); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java new file mode 100644 index 00000000..bf04d50c --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java @@ -0,0 +1,115 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.cp.util.json; + +import java.lang.reflect.Type; + +import com.google.gson.*; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.cp.bean.WxCpUser; + +/** + * @author Daniel Qian + */ +public class WxCpUserGsonAdapter implements JsonDeserializer, JsonSerializer { + + public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + JsonObject o = json.getAsJsonObject(); + WxCpUser user = new WxCpUser(); + user.setUserId(GsonHelper.getString(o, "userid")); + user.setName(GsonHelper.getString(o, "name")); + + if(o.get("department") != null) { + JsonArray departJsonArray = o.get("department").getAsJsonArray(); + Integer[] departIds = new Integer[departJsonArray.size()]; + int i = 0; + for (JsonElement jsonElement : departJsonArray) { + departIds[i++] = jsonElement.getAsInt(); + } + user.setDepartIds(departIds); + } + + user.setPosition(GsonHelper.getString(o, "position")); + user.setMobile(GsonHelper.getString(o, "mobile")); + Integer gender = GsonHelper.getInteger(o, "gender"); + if (new Integer(1).equals(gender)) { + user.setGender("男"); + } else if (new Integer(2).equals(gender)) { + user.setGender("女"); + } else { + user.setGender("未知"); + } + user.setTel(GsonHelper.getString(o, "tel")); + user.setEmail(GsonHelper.getString(o, "email")); + user.setWeiXinId(GsonHelper.getString(o, "weixinid")); + + if (GsonHelper.isNotNull(o.get("extattr"))) { + JsonArray attrJsonElements = o.get("extattr").getAsJsonObject().get("attrs").getAsJsonArray(); + for (JsonElement attrJsonElement : attrJsonElements) { + WxCpUser.Attr attr = new WxCpUser.Attr( + GsonHelper.getString(attrJsonElement.getAsJsonObject(), "name"), + GsonHelper.getString(attrJsonElement.getAsJsonObject(), "value") + ); + user.getExtAttrs().add(attr); + } + } + return user; + } + + @Override + public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationContext context) { + JsonObject o = new JsonObject(); + if (user.getUserId() != null) { + o.addProperty("userid", user.getUserId()); + } + if (user.getName() != null) { + o.addProperty("name", user.getName()); + } + if (user.getDepartIds() != null) { + JsonArray jsonArray = new JsonArray(); + for (Integer departId : user.getDepartIds()) { + jsonArray.add(new JsonPrimitive(departId)); + } + o.add("department", jsonArray); + } + if (user.getPosition() != null) { + o.addProperty("position", user.getPosition()); + } + if (user.getMobile() != null) { + o.addProperty("mobile", user.getMobile()); + } + if (user.getGender() != null) { + o.addProperty("gender", user.getGender().equals("男") ? 0 : 1); + } + if (user.getTel() != null) { + o.addProperty("tel", user.getTel()); + } + if (user.getEmail() != null) { + o.addProperty("email", user.getEmail()); + } + if (user.getWeiXinId() != null) { + o.addProperty("weixinid", user.getWeiXinId()); + } + if (user.getExtAttrs().size() > 0) { + JsonArray attrsJsonArray = new JsonArray(); + for (WxCpUser.Attr attr : user.getExtAttrs()) { + JsonObject attrJson = new JsonObject(); + attrJson.addProperty("name", attr.getName()); + attrJson.addProperty("value", attr.getValue()); + attrsJsonArray.add(attrJson); + } + JsonObject attrsJson = new JsonObject(); + attrsJson.add("attrs", attrsJsonArray); + o.add("extattr", attrsJson); + } + return o; + } + +} diff --git a/src/main/java/me/chanjar/weixin/util/xml/XmlTransformer.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XmlTransformer.java similarity index 87% rename from src/main/java/me/chanjar/weixin/util/xml/XmlTransformer.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XmlTransformer.java index 026cc0a5..39914f44 100644 --- a/src/main/java/me/chanjar/weixin/util/xml/XmlTransformer.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XmlTransformer.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.util.xml; +package me.chanjar.weixin.cp.util.xml; import java.io.IOException; import java.io.InputStream; @@ -8,7 +8,7 @@ import java.io.Writer; import javax.xml.bind.*; -import me.chanjar.weixin.bean.*; +import me.chanjar.weixin.cp.bean.*; import org.xml.sax.InputSource; import com.sun.xml.bind.marshaller.CharacterEscapeHandler; @@ -77,14 +77,13 @@ public class XmlTransformer { */ try { return JAXBContext.newInstance( - WxXmlOutMessage.class, - WxXmlOutImageMessage.class, - WxXmlOutMewsMessage.class, - WxXmlOutMusicMessage.class, - WxXmlOutTextMessage.class, - WxXmlOutVideoMessage.class, - WxXmlOutVoiceMessage.class, - WxXmlMessage.class); + WxCpXmlOutMessage.class, + WxCpXmlOutImageMessage.class, + WxCpXmlOutMewsMessage.class, + WxCpXmlOutTextMessage.class, + WxCpXmlOutVideoMessage.class, + WxCpXmlOutVoiceMessage.class, + WxCpXmlMessage.class); } catch (JAXBException e) { throw new RuntimeException(e); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java new file mode 100644 index 00000000..00b890d9 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java @@ -0,0 +1,84 @@ +package me.chanjar.weixin.cp.api; + +import java.io.InputStream; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import com.google.inject.Binder; +import com.google.inject.Module; +import org.xml.sax.InputSource; + +public class ApiTestModule implements Module { + + @Override + public void configure(Binder binder) { + try { + InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml"); + WxXmlCpInMemoryConfigStorage config = fromXml(WxXmlCpInMemoryConfigStorage.class, is1); + WxCpServiceImpl wxService = new WxCpServiceImpl(); + wxService.setWxCpConfigStorage(config); + + binder.bind(WxCpServiceImpl.class).toInstance(wxService); + binder.bind(WxCpConfigStorage.class).toInstance(config); + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } + + public static T fromXml(Class clazz, InputStream is) throws JAXBException { + Unmarshaller um = JAXBContext.newInstance(clazz).createUnmarshaller(); + InputSource inputSource = new InputSource(is); + inputSource.setEncoding("utf-8"); + T object = (T) um.unmarshal(inputSource); + return object; + } + + @XmlRootElement(name = "xml") + @XmlAccessorType(XmlAccessType.FIELD) + public static class WxXmlCpInMemoryConfigStorage extends WxCpInMemoryConfigStorage { + + protected String userId; + + protected String departmentId; + + protected String tagId; + + public String getUserId() { + return userId; + } + public void setUserId(String userId) { + this.userId = userId; + } + + public String getDepartmentId() { + return departmentId; + } + + public void setDepartmentId(String departmentId) { + this.departmentId = departmentId; + } + + public String getTagId() { + return tagId; + } + + public void setTagId(String tagId) { + this.tagId = tagId; + } + + @Override + public String toString() { + return super.toString() + " > WxXmlCpConfigStorage{" + + "userId='" + userId + '\'' + + ", departmentId='" + departmentId + '\'' + + ", tagId='" + tagId + '\'' + + '}'; + } + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java new file mode 100644 index 00000000..07d7d0a6 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java @@ -0,0 +1,35 @@ +package me.chanjar.weixin.cp.api; + +import org.apache.commons.lang3.StringUtils; +import org.testng.Assert; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import me.chanjar.weixin.common.exception.WxErrorException; + +import com.google.inject.Inject; + +/** + * 基础API测试 + * @author Daniel Qian + * + */ +@Test(groups = "baseAPI") +@Guice(modules = ApiTestModule.class) +public class WxCpBaseAPITest { + + @Inject + protected WxCpServiceImpl wxService; + + public void testRefreshAccessToken() throws WxErrorException { + WxCpConfigStorage configStorage = wxService.wxCpConfigStorage; + String before = configStorage.getAccessToken(); + wxService.accessTokenRefresh(); + + String after = configStorage.getAccessToken(); + + Assert.assertNotEquals(before, after); + Assert.assertTrue(StringUtils.isNotBlank(after)); + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java new file mode 100644 index 00000000..28cf15b0 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java @@ -0,0 +1,63 @@ +package me.chanjar.weixin.cp.api; + +import java.util.List; + +import me.chanjar.weixin.cp.bean.WxCpDepart; +import org.testng.Assert; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import me.chanjar.weixin.common.exception.WxErrorException; + +import com.google.inject.Inject; + +/** + * 测试部门接口 + * + * @author Daniel Qian + */ +@Test(groups = "departAPI", dependsOnGroups = "baseAPI") +@Guice(modules = ApiTestModule.class) +public class WxCpDepartAPITest { + + @Inject + protected WxCpServiceImpl wxCpService; + + protected WxCpDepart depart; + + public void testDepartCreate() throws WxErrorException { + WxCpDepart depart = new WxCpDepart(); + depart.setName("子部门" + System.currentTimeMillis()); + depart.setParentId(1); + depart.setOrder(1); + Integer departId = wxCpService.departCreate(depart); + } + + @Test(dependsOnMethods = "testDepartCreate") + public void testDepartGet() throws WxErrorException { + System.out.println("=================获取部门"); + List departList = wxCpService.departGet(); + Assert.assertNotNull(departList); + Assert.assertTrue(departList.size() > 0); + for (WxCpDepart g : departList) { + depart = g; + System.out.println(depart.getId() + ":" + depart.getName()); + Assert.assertNotNull(g.getName()); + } + } + + @Test(dependsOnMethods = { "testDepartGet", "testDepartCreate" }) + public void testDepartUpdate() throws WxErrorException { + System.out.println("=================更新部门"); + depart.setName("子部门改名" + System.currentTimeMillis()); + wxCpService.departUpdate(depart); + } + + @Test(dependsOnMethods = "testDepartUpdate") + public void testDepartDelete() throws WxErrorException { + System.out.println("=================删除部门"); + System.out.println(depart.getId() + ":" + depart.getName()); + wxCpService.departDelete(depart.getId()); + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java new file mode 100644 index 00000000..336e11b7 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java @@ -0,0 +1,73 @@ +package me.chanjar.weixin.cp.api; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import me.chanjar.weixin.common.exception.WxErrorException; + +import com.google.inject.Inject; + +/** + * 测试多媒体文件上传下载 + * @author Daniel Qian + * + */ +//@Test(groups="mediaAPI", dependsOnGroups="baseAPI") +@Test +@Guice(modules = ApiTestModule.class) +public class WxCpMediaAPITest { + + @Inject + protected WxCpServiceImpl wxService; + + private List media_ids = new ArrayList(); + + @Test(dataProvider="uploadMedia") + public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { + InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName); + WxMediaUploadResult res = wxService.mediaUpload(mediaType, fileType, inputStream); + Assert.assertNotNull(res.getType()); + Assert.assertNotNull(res.getCreatedAt()); + Assert.assertTrue(res.getMediaId() != null || res.getThumbMediaId() != null); + + if (res.getMediaId() != null) { + media_ids.add(res.getMediaId()); + } + if (res.getThumbMediaId() != null) { + media_ids.add(res.getThumbMediaId()); + } + } + + @DataProvider + public Object[][] uploadMedia() { + return new Object[][] { + new Object[] { WxCpConsts.MEDIA_IMAGE, WxCpConsts.FILE_JPG, "mm.jpeg" }, + new Object[] { WxCpConsts.MEDIA_VOICE, WxCpConsts.FILE_MP3, "mm.mp3" }, + new Object[] { WxCpConsts.MEDIA_VIDEO, WxCpConsts.FILE_MP4, "mm.mp4" }, + new Object[] { WxCpConsts.MEDIA_FILE, WxCpConsts.FILE_JPG, "mm.jpeg" } + }; + } + + @Test(dependsOnMethods = { "testUploadMedia" }, dataProvider="downloadMedia") + public void testDownloadMedia(String media_id) throws WxErrorException { + wxService.mediaDownload(media_id); + } + + @DataProvider + public Object[][] downloadMedia() { + Object[][] params = new Object[this.media_ids.size()][]; + for (int i = 0; i < this.media_ids.size(); i++) { + params[i] = new Object[] { this.media_ids.get(i) }; + } + return params; + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java new file mode 100644 index 00000000..01acca71 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java @@ -0,0 +1,42 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.cp.bean.WxCpMessage; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import me.chanjar.weixin.common.exception.WxErrorException; + +import com.google.inject.Inject; + +/*** + * 测试发送消息 + * @author Daniel Qian + * + */ +@Test(groups="customMessageAPI", dependsOnGroups = "baseAPI") +@Guice(modules = ApiTestModule.class) +public class WxCpMessageAPITest { + + @Inject + protected WxCpServiceImpl wxService; + + public void testSendCustomMessage() throws WxErrorException { + ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlCpInMemoryConfigStorage) wxService.wxCpConfigStorage; + WxCpMessage message1 = new WxCpMessage(); + message1.setAgentId(configStorage.getAgentId()); + message1.setMsgType(WxCpConsts.CUSTOM_MSG_TEXT); + message1.setToUser(configStorage.getUserId()); + message1.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); + wxService.messageSend(message1); + + WxCpMessage message2 = WxCpMessage + .TEXT() + .agentId(configStorage.getAgentId()) + .toUser(configStorage.getUserId()) + .content("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World") + .build(); + wxService.messageSend(message2); + + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java new file mode 100644 index 00000000..6ad6f62c --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java @@ -0,0 +1,158 @@ +package me.chanjar.weixin.cp.api; + +import java.util.Map; + +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * 测试消息路由器 + * @author Daniel Qian + * + */ +@Test +public class WxCpMessageRouterTest { + + @Test(enabled = false) + public void prepare(boolean async, StringBuffer sb, WxCpMessageRouter router) { + router + .rule() + .async(async) + .msgType(WxCpConsts.XML_MSG_TEXT).event(WxCpConsts.EVT_CLICK).eventKey("KEY_1").content("CONTENT_1") + .handler(new WxEchoCpMessageHandler(sb, "COMBINE_4")) + .end() + .rule() + .async(async) + .msgType(WxCpConsts.XML_MSG_TEXT).event(WxCpConsts.EVT_CLICK).eventKey("KEY_1") + .handler(new WxEchoCpMessageHandler(sb, "COMBINE_3")) + .end() + .rule() + .async(async) + .msgType(WxCpConsts.XML_MSG_TEXT).event(WxCpConsts.EVT_CLICK) + .handler(new WxEchoCpMessageHandler(sb, "COMBINE_2")) + .end() + .rule().async(async).msgType(WxCpConsts.XML_MSG_TEXT).handler(new WxEchoCpMessageHandler(sb, WxCpConsts.XML_MSG_TEXT)).end() + .rule().async(async).event(WxCpConsts.EVT_CLICK).handler(new WxEchoCpMessageHandler(sb, WxCpConsts.EVT_CLICK)).end() + .rule().async(async).eventKey("KEY_1").handler(new WxEchoCpMessageHandler(sb, "KEY_1")).end() + .rule().async(async).content("CONTENT_1").handler(new WxEchoCpMessageHandler(sb, "CONTENT_1")).end() + .rule().async(async).rContent(".*bc.*").handler(new WxEchoCpMessageHandler(sb, "abcd")).end() + .rule().async(async).handler(new WxEchoCpMessageHandler(sb, "ALL")).end(); + ; + } + + @Test(dataProvider="messages-1") + public void testSync(WxCpXmlMessage message, String expected) { + StringBuffer sb = new StringBuffer(); + WxCpMessageRouter router = new WxCpMessageRouter(); + prepare(false, sb, router); + router.route(message); + Assert.assertEquals(sb.toString(), expected); + } + + @Test(dataProvider="messages-1") + public void testAsync(WxCpXmlMessage message, String expected) throws InterruptedException { + StringBuffer sb = new StringBuffer(); + WxCpMessageRouter router = new WxCpMessageRouter(); + prepare(true, sb, router); + router.route(message); + Thread.sleep(500l); + Assert.assertEquals(sb.toString(), expected); + } + + public void testConcurrency() throws InterruptedException { + final WxCpMessageRouter router = new WxCpMessageRouter(); + router.rule().handler(new WxCpMessageHandler() { + @Override + public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context) { + return null; + } + }).end(); + + final WxCpXmlMessage m = new WxCpXmlMessage(); + Runnable r = new Runnable() { + @Override + public void run() { + router.route(m); + try { + Thread.sleep(1000l); + } catch (InterruptedException e) { + } + } + }; + for (int i = 0; i < 10; i++) { + new Thread(r).start(); + } + + Thread.sleep(1000l * 2); + } + @DataProvider(name="messages-1") + public Object[][] messages2() { + WxCpXmlMessage message1 = new WxCpXmlMessage(); + message1.setMsgType(WxCpConsts.XML_MSG_TEXT); + + WxCpXmlMessage message2 = new WxCpXmlMessage(); + message2.setEvent(WxCpConsts.EVT_CLICK); + + WxCpXmlMessage message3 = new WxCpXmlMessage(); + message3.setEventKey("KEY_1"); + + WxCpXmlMessage message4 = new WxCpXmlMessage(); + message4.setContent("CONTENT_1"); + + WxCpXmlMessage message5 = new WxCpXmlMessage(); + message5.setContent("BLA"); + + WxCpXmlMessage message6 = new WxCpXmlMessage(); + message6.setContent("abcd"); + + WxCpXmlMessage c2 = new WxCpXmlMessage(); + c2.setMsgType(WxCpConsts.XML_MSG_TEXT); + c2.setEvent(WxCpConsts.EVT_CLICK); + + WxCpXmlMessage c3 = new WxCpXmlMessage(); + c3.setMsgType(WxCpConsts.XML_MSG_TEXT); + c3.setEvent(WxCpConsts.EVT_CLICK); + c3.setEventKey("KEY_1"); + + WxCpXmlMessage c4 = new WxCpXmlMessage(); + c4.setMsgType(WxCpConsts.XML_MSG_TEXT); + c4.setEvent(WxCpConsts.EVT_CLICK); + c4.setEventKey("KEY_1"); + c4.setContent("CONTENT_1"); + + return new Object[][] { + new Object[] { message1, WxCpConsts.XML_MSG_TEXT + "," }, + new Object[] { message2, WxCpConsts.EVT_CLICK + "," }, + new Object[] { message3, "KEY_1," }, + new Object[] { message4, "CONTENT_1," }, + new Object[] { message5, "ALL," }, + new Object[] { message6, "abcd," }, + new Object[] { c2, "COMBINE_2," }, + new Object[] { c3, "COMBINE_3," }, + new Object[] { c4, "COMBINE_4," } + }; + + } + + public static class WxEchoCpMessageHandler implements WxCpMessageHandler { + + private StringBuffer sb; + private String echoStr; + + public WxEchoCpMessageHandler(StringBuffer sb, String echoStr) { + this.sb = sb; + this.echoStr = echoStr; + } + + @Override + public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context) { + sb.append(this.echoStr).append(','); + return null; + } + + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java new file mode 100644 index 00000000..0bb7dba9 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java @@ -0,0 +1,66 @@ +package me.chanjar.weixin.cp.api; + +import com.google.inject.Inject; +import me.chanjar.weixin.cp.bean.WxCpTag; +import me.chanjar.weixin.cp.bean.WxCpUser; +import org.testng.Assert; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.List; + +@Test(groups = "departAPI", dependsOnGroups = "baseAPI") +@Guice(modules = ApiTestModule.class) +public class WxCpTagAPITest { + + @Inject + protected WxCpServiceImpl wxService; + + @Inject + protected WxCpConfigStorage configStorage; + + protected String tagId; + + public void testTagCreate() throws Exception { + tagId = wxService.tagCreate("测试标签4"); + System.out.println(tagId); + } + + @Test(dependsOnMethods = "testTagCreate") + public void testTagUpdate() throws Exception { + wxService.tagUpdate(tagId, "测试标签-改名"); + } + + @Test(dependsOnMethods = "testTagUpdate") + public void testTagGet() throws Exception { + List tags = wxService.tagGet(); + Assert.assertNotEquals(tags.size(), 0); + } + + @Test(dependsOnMethods = "testTagGet") + public void testTagAddUsers() throws Exception { + List userIds = new ArrayList(); + userIds.add(((ApiTestModule.WxXmlCpInMemoryConfigStorage)configStorage).getUserId()); + wxService.tagAddUsers(tagId, userIds); + } + + @Test(dependsOnMethods = "testTagAddUsers") + public void testTagGetUsers() throws Exception { + List users = wxService.tagGetUsers(tagId); + Assert.assertNotEquals(users.size(), 0); + } + + @Test(dependsOnMethods = "testTagGetUsers") + public void testTagRemoveUsers() throws Exception { + List userIds = new ArrayList(); + userIds.add(((ApiTestModule.WxXmlCpInMemoryConfigStorage)configStorage).getUserId()); + wxService.tagRemoveUsers(tagId, userIds); + } + + @Test(dependsOnMethods = "testTagRemoveUsers") + public void testTagDelete() throws Exception { + wxService.tagDelete(tagId); + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java new file mode 100644 index 00000000..9efb8a09 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java @@ -0,0 +1,66 @@ +package me.chanjar.weixin.cp.api; + +import com.google.inject.Inject; +import me.chanjar.weixin.cp.bean.WxCpDepart; +import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.common.exception.WxErrorException; +import org.testng.Assert; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.util.List; + +/** + * 测试用户接口 + * + * @author Daniel Qian + */ +@Test(groups = "userAPI", dependsOnGroups = "baseAPI") +@Guice(modules = ApiTestModule.class) +public class WxCpUserAPITest { + + @Inject + protected WxCpServiceImpl wxCpService; + + protected WxCpDepart depart; + + public void testUserCreate() throws WxErrorException { + WxCpUser user = new WxCpUser(); + user.setUserId("xiaohe.yang"); + user.setName("杨宝"); + user.setDepartIds(new Integer[] { 9, 8 }); + user.setEmail("yangxiaohe@ddd.com"); + user.setGender("女"); + user.setMobile("13564684979"); + user.setPosition("老婆"); + user.setTel("3300393"); + user.addExtAttr("爱好", "老公"); + wxCpService.userCreate(user); + } + + @Test(dependsOnMethods = "testUserCreate") + public void testUserUpdate() throws WxErrorException { + WxCpUser user = new WxCpUser(); + user.setUserId("xiaohe.yang"); + user.setName("杨宝"); + user.addExtAttr("爱好", "老公2"); + wxCpService.userUpdate(user); + } + + @Test(dependsOnMethods = "testUserUpdate") + public void testUserGet() throws WxErrorException { + WxCpUser user = wxCpService.userGet("xiaohe.yang"); + Assert.assertNotNull(user); + } + + @Test(dependsOnMethods = "testUserGet") + public void testDepartGetUsers() throws WxErrorException { + List users = wxCpService.departGetUsers(1, true, 0); + Assert.assertNotEquals(users.size(), 0); + } + + @Test(dependsOnMethods = "testDepartGetUsers") + public void testUserDelete() throws WxErrorException { + wxCpService.userDelete("xiaohe.yang"); + } +} diff --git a/src/test/java/me/chanjar/weixin/api/WxMenuAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java similarity index 70% rename from src/test/java/me/chanjar/weixin/api/WxMenuAPITest.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java index f85f2ed4..ebb292e2 100644 --- a/src/test/java/me/chanjar/weixin/api/WxMenuAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java @@ -1,7 +1,8 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.cp.api; import javax.xml.bind.JAXBException; +import me.chanjar.weixin.common.bean.WxMenu; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Guice; @@ -9,13 +10,12 @@ import org.testng.annotations.Test; import com.google.inject.Inject; -import me.chanjar.weixin.bean.WxMenu; -import me.chanjar.weixin.bean.WxMenu.WxMenuButton; -import me.chanjar.weixin.exception.WxErrorException; +import me.chanjar.weixin.common.bean.WxMenu.WxMenuButton; +import me.chanjar.weixin.common.exception.WxErrorException; /** * 测试菜单 - * @author chanjarster + * @author Daniel Qian * */ @Test(groups="menuAPI", dependsOnGroups="baseAPI") @@ -23,7 +23,7 @@ import me.chanjar.weixin.exception.WxErrorException; public class WxMenuAPITest { @Inject - protected WxServiceImpl wxService; + protected WxCpServiceImpl wxService; @Test(dataProvider = "menu") public void testCreateMenu(WxMenu wxMenu) throws WxErrorException { @@ -44,40 +44,40 @@ public class WxMenuAPITest { public Object[][] getMenu() throws JAXBException { WxMenu menu = new WxMenu(); WxMenuButton button1 = new WxMenuButton(); - button1.setType("click"); + button1.setType(WxCpConsts.BUTTON_CLICK); button1.setName("今日歌曲"); button1.setKey("V1001_TODAY_MUSIC"); WxMenuButton button2 = new WxMenuButton(); - button2.setType("click"); + button2.setType(WxCpConsts.BUTTON_CLICK); button2.setName("歌手简介"); button2.setKey("V1001_TODAY_SINGER"); WxMenuButton button3 = new WxMenuButton(); button3.setName("菜单"); - menu.getButton().add(button1); - menu.getButton().add(button2); - menu.getButton().add(button3); + menu.getButtons().add(button1); + menu.getButtons().add(button2); + menu.getButtons().add(button3); WxMenuButton button31 = new WxMenuButton(); - button31.setType("view"); + button31.setType(WxCpConsts.BUTTON_VIEW); button31.setName("搜索"); button31.setUrl("http://www.soso.com/"); WxMenuButton button32 = new WxMenuButton(); - button32.setType("view"); + button32.setType(WxCpConsts.BUTTON_VIEW); button32.setName("视频"); button32.setUrl("http://v.qq.com/"); WxMenuButton button33 = new WxMenuButton(); - button33.setType("click"); + button33.setType(WxCpConsts.BUTTON_CLICK); button33.setName("赞一下我们"); button33.setKey("V1001_GOOD"); - button3.getSub_button().add(button31); - button3.getSub_button().add(button32); - button3.getSub_button().add(button33); + button3.getSubButtons().add(button31); + button3.getSubButtons().add(button32); + button3.getSubButtons().add(button33); return new Object[][] { new Object[] { diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java new file mode 100644 index 00000000..56fca755 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java @@ -0,0 +1,108 @@ +package me.chanjar.weixin.cp.bean; + +import me.chanjar.weixin.cp.api.WxCpConsts; +import org.testng.Assert; +import org.testng.annotations.Test; + +import me.chanjar.weixin.cp.bean.WxCpMessage.WxArticle; + +@Test +public class WxCpMessageTest { + + public void testTextReply() { + WxCpMessage reply = new WxCpMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxCpConsts.CUSTOM_MSG_TEXT); + reply.setContent("sfsfdsdf"); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); + } + + public void testTextBuild() { + WxCpMessage reply = WxCpMessage.TEXT().toUser("OPENID").content("sfsfdsdf").build(); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); + } + + public void testImageReply() { + WxCpMessage reply = new WxCpMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxCpConsts.CUSTOM_MSG_IMAGE); + reply.setMediaId("MEDIA_ID"); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); + } + + public void testImageBuild() { + WxCpMessage reply = WxCpMessage.IMAGE().toUser("OPENID").mediaId("MEDIA_ID").build(); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); + } + + public void testVoiceReply() { + WxCpMessage reply = new WxCpMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxCpConsts.CUSTOM_MSG_VOICE); + reply.setMediaId("MEDIA_ID"); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"voice\",\"voice\":{\"media_id\":\"MEDIA_ID\"}}"); + } + + public void testVoiceBuild() { + WxCpMessage reply = WxCpMessage.VOICE().toUser("OPENID").mediaId("MEDIA_ID").build(); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"voice\",\"voice\":{\"media_id\":\"MEDIA_ID\"}}"); + } + + public void testVideoReply() { + WxCpMessage reply = new WxCpMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxCpConsts.CUSTOM_MSG_VIDEO); + reply.setMediaId("MEDIA_ID"); + reply.setThumbMediaId("MEDIA_ID"); + reply.setTitle("TITLE"); + reply.setDescription("DESCRIPTION"); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"video\",\"video\":{\"media_id\":\"MEDIA_ID\",\"thumb_media_id\":\"MEDIA_ID\",\"title\":\"TITLE\",\"description\":\"DESCRIPTION\"}}"); + } + + public void testVideoBuild() { + WxCpMessage reply = WxCpMessage.VIDEO().toUser("OPENID").title("TITLE").mediaId("MEDIA_ID").thumbMediaId("MEDIA_ID").description("DESCRIPTION").build(); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"video\",\"video\":{\"media_id\":\"MEDIA_ID\",\"thumb_media_id\":\"MEDIA_ID\",\"title\":\"TITLE\",\"description\":\"DESCRIPTION\"}}"); + } + + public void testNewsReply() { + WxCpMessage reply = new WxCpMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxCpConsts.CUSTOM_MSG_NEWS); + + WxArticle article1 = new WxArticle(); + article1.setUrl("URL"); + article1.setPicUrl("PIC_URL"); + article1.setDescription("Is Really A Happy Day"); + article1.setTitle("Happy Day"); + reply.getArticles().add(article1); + + WxArticle article2 = new WxArticle(); + article2.setUrl("URL"); + article2.setPicUrl("PIC_URL"); + article2.setDescription("Is Really A Happy Day"); + article2.setTitle("Happy Day"); + reply.getArticles().add(article2); + + + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}"); + } + + public void testNewsBuild() { + WxArticle article1 = new WxArticle(); + article1.setUrl("URL"); + article1.setPicUrl("PIC_URL"); + article1.setDescription("Is Really A Happy Day"); + article1.setTitle("Happy Day"); + + WxArticle article2 = new WxArticle(); + article2.setUrl("URL"); + article2.setPicUrl("PIC_URL"); + article2.setDescription("Is Really A Happy Day"); + article2.setTitle("Happy Day"); + + WxCpMessage reply = WxCpMessage.NEWS().toUser("OPENID").addArticle(article1).addArticle(article2).build(); + + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}"); + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java new file mode 100644 index 00000000..d356126f --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java @@ -0,0 +1,91 @@ +package me.chanjar.weixin.cp.bean; + +import me.chanjar.weixin.cp.api.WxCpConsts; +import org.testng.Assert; +import org.testng.annotations.Test; + +@Test +public class WxCpXmlMessageTest { + + public void testFromXml() { + + String xml = "" + + "" + + " " + + "1348831860" + + "" + + "" + + "1234567890123456" + + "" + + "" + + "" + + "" + + "23.134521" + + "113.358803" + + "20" + + "" + + "" + + "" + + "<![CDATA[公众平台官网链接]]>" + + "" + + "" + + "" + + "23.137466" + + "113.352425" + + "119.385040" + + "" + + " " + + " " + + "" + + "" + + " 1\n" + + " " + + " " + + " " + + " " + + " " + + "" + + "" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "" + + ""; + WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml); + Assert.assertEquals(wxMessage.getToUserName(), "toUser"); + Assert.assertEquals(wxMessage.getFromUserName(), "fromUser"); + Assert.assertEquals(wxMessage.getCreateTime(), new Long(1348831860l)); + Assert.assertEquals(wxMessage.getMsgType(), WxCpConsts.XML_MSG_TEXT); + Assert.assertEquals(wxMessage.getContent(), "this is a test"); + Assert.assertEquals(wxMessage.getMsgId(), new Long(1234567890123456l)); + Assert.assertEquals(wxMessage.getPicUrl(), "this is a url"); + Assert.assertEquals(wxMessage.getMediaId(), "media_id"); + Assert.assertEquals(wxMessage.getFormat(), "Format"); + Assert.assertEquals(wxMessage.getThumbMediaId(), "thumb_media_id"); + Assert.assertEquals(wxMessage.getLocationX(), new Double(23.134521d)); + Assert.assertEquals(wxMessage.getLocationY(), new Double(113.358803d)); + Assert.assertEquals(wxMessage.getScale(), new Double(20)); + Assert.assertEquals(wxMessage.getLabel(), "位置信息"); + Assert.assertEquals(wxMessage.getDescription(), "公众平台官网链接"); + Assert.assertEquals(wxMessage.getUrl(), "url"); + Assert.assertEquals(wxMessage.getTitle(), "公众平台官网链接"); + Assert.assertEquals(wxMessage.getEvent(), "subscribe"); + Assert.assertEquals(wxMessage.getEventKey(), "qrscene_123123"); + Assert.assertEquals(wxMessage.getTicket(), "TICKET"); + Assert.assertEquals(wxMessage.getLatitude(), new Double(23.137466)); + Assert.assertEquals(wxMessage.getLongitude(), new Double(113.352425)); + Assert.assertEquals(wxMessage.getPrecision(), new Double(119.385040)); + Assert.assertEquals(wxMessage.getScanCodeInfo().getScanType(), "qrcode"); + Assert.assertEquals(wxMessage.getScanCodeInfo().getScanResult(), "1"); + Assert.assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(1l)); + Assert.assertEquals(wxMessage.getSendPicsInfo().getPicList().get(0).getPicMd5Sum(), "1b5f7c23b5bf75682a53e7b6d163e185"); + Assert.assertEquals(wxMessage.getSendLocationInfo().getLocationX(), "23"); + Assert.assertEquals(wxMessage.getSendLocationInfo().getLocationY(), "113"); + Assert.assertEquals(wxMessage.getSendLocationInfo().getScale(), "15"); + Assert.assertEquals(wxMessage.getSendLocationInfo().getLabel(), " 广州市海珠区客村艺苑路 106号"); + Assert.assertEquals(wxMessage.getSendLocationInfo().getPoiname(), "wo de poi"); + } + +} diff --git a/src/test/java/me/chanjar/weixin/bean/WxXmlOutImageMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java similarity index 81% rename from src/test/java/me/chanjar/weixin/bean/WxXmlOutImageMessageTest.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java index a36b98c4..9f97e4b8 100644 --- a/src/test/java/me/chanjar/weixin/bean/WxXmlOutImageMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java @@ -1,15 +1,13 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.cp.bean; -import me.chanjar.weixin.bean.WxXmlOutImageMessage; -import me.chanjar.weixin.bean.WxXmlOutMessage; import org.testng.Assert; import org.testng.annotations.Test; @Test -public class WxXmlOutImageMessageTest { +public class WxCpXmlOutImageMessageTest { public void test() { - WxXmlOutImageMessage m = new WxXmlOutImageMessage(); + WxCpXmlOutImageMessage m = new WxCpXmlOutImageMessage(); m.setMediaId("ddfefesfsdfef"); m.setCreateTime(1122l); m.setFromUserName("from"); @@ -28,7 +26,7 @@ public class WxXmlOutImageMessageTest { } public void testBuild() { - WxXmlOutImageMessage m = WxXmlOutMessage.IMAGE().mediaId("ddfefesfsdfef").fromUser("from").touser("to").build(); + WxCpXmlOutImageMessage m = WxCpXmlOutMessage.IMAGE().mediaId("ddfefesfsdfef").fromUser("from").toUser("to").build(); String expected = "" + "" + "" diff --git a/src/test/java/me/chanjar/weixin/bean/WxXmlOutINewsMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java similarity index 81% rename from src/test/java/me/chanjar/weixin/bean/WxXmlOutINewsMessageTest.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java index 70073a56..f72c76b3 100644 --- a/src/test/java/me/chanjar/weixin/bean/WxXmlOutINewsMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java @@ -1,20 +1,18 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.cp.bean; -import me.chanjar.weixin.bean.WxXmlOutMessage; -import me.chanjar.weixin.bean.WxXmlOutMewsMessage; import org.testng.Assert; import org.testng.annotations.Test; @Test -public class WxXmlOutINewsMessageTest { +public class WxCpXmlOutNewsMessageTest { public void test() { - WxXmlOutMewsMessage m = new WxXmlOutMewsMessage(); + WxCpXmlOutMewsMessage m = new WxCpXmlOutMewsMessage(); m.setCreateTime(1122l); m.setFromUserName("fromUser"); m.setToUserName("toUser"); - WxXmlOutMewsMessage.Item item = new WxXmlOutMewsMessage.Item(); + WxCpXmlOutMewsMessage.Item item = new WxCpXmlOutMewsMessage.Item(); item.setDescription("description"); item.setPicUrl("picUrl"); item.setTitle("title"); @@ -29,18 +27,18 @@ public class WxXmlOutINewsMessageTest { + "" + " 2" + " " - + " " + + " " + " <![CDATA[title]]>" + " " + " " + " " - + " " - + " " + + " " + + " " + " <![CDATA[title]]>" + " " + " " + " " - + " " + + " " + " " + ""; System.out.println(m.toXml()); @@ -48,15 +46,15 @@ public class WxXmlOutINewsMessageTest { } public void testBuild() { - WxXmlOutMewsMessage.Item item = new WxXmlOutMewsMessage.Item(); + WxCpXmlOutMewsMessage.Item item = new WxCpXmlOutMewsMessage.Item(); item.setDescription("description"); item.setPicUrl("picUrl"); item.setTitle("title"); item.setUrl("url"); - WxXmlOutMewsMessage m = WxXmlOutMessage.NEWS() + WxCpXmlOutMewsMessage m = WxCpXmlOutMessage.NEWS() .fromUser("fromUser") - .touser("toUser") + .toUser("toUser") .addArticle(item) .addArticle(item) .build(); @@ -68,18 +66,18 @@ public class WxXmlOutINewsMessageTest { + "" + " 2" + " " - + " " + + " " + " <![CDATA[title]]>" + " " + " " + " " - + " " - + " " + + " " + + " " + " <![CDATA[title]]>" + " " + " " + " " - + " " + + " " + " " + ""; System.out.println(m.toXml()); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java new file mode 100644 index 00000000..4dce4f16 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java @@ -0,0 +1,52 @@ +package me.chanjar.weixin.cp.bean; + +import org.testng.Assert; +import org.testng.annotations.Test; + +@Test +public class WxCpXmlOutTextMessageTest { + + public void test() { + WxCpXmlOutTextMessage m = new WxCpXmlOutTextMessage(); + m.setContent("content"); + m.setCreateTime(1122l); + m.setFromUserName("from"); + m.setToUserName("to"); + + String expected = "" + + "" + + "" + + "" + + "1122" + + "" + + "" + + ""; + System.out.println(m.toXml()); + Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); + } + + public void testBuild() { + WxCpXmlOutTextMessage m = WxCpXmlOutMessage.TEXT().content("content").fromUser("from").toUser("to").build(); + String expected = "" + + "" + + "" + + "" + + "1122" + + "" + + "" + + ""; + System.out.println(m.toXml()); + Assert.assertEquals( + m + .toXml() + .replaceAll("\\s", "") + .replaceAll(".*?", ""), + expected + .replaceAll("\\s", "") + .replaceAll(".*?", "") + ); + + } + + +} diff --git a/src/test/java/me/chanjar/weixin/bean/WxXmlOutIVideoMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java similarity index 86% rename from src/test/java/me/chanjar/weixin/bean/WxXmlOutIVideoMessageTest.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java index 40c82072..b5ba2456 100644 --- a/src/test/java/me/chanjar/weixin/bean/WxXmlOutIVideoMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java @@ -1,15 +1,13 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.cp.bean; -import me.chanjar.weixin.bean.WxXmlOutMessage; -import me.chanjar.weixin.bean.WxXmlOutVideoMessage; import org.testng.Assert; import org.testng.annotations.Test; @Test -public class WxXmlOutIVideoMessageTest { +public class WxCpXmlOutVideoMessageTest { public void test() { - WxXmlOutVideoMessage m = new WxXmlOutVideoMessage(); + WxCpXmlOutVideoMessage m = new WxCpXmlOutVideoMessage(); m.setMediaId("media_id"); m.setTitle("title"); m.setDescription("ddfff"); @@ -34,10 +32,10 @@ public class WxXmlOutIVideoMessageTest { } public void testBuild() { - WxXmlOutVideoMessage m = WxXmlOutMessage.VIDEO() + WxCpXmlOutVideoMessage m = WxCpXmlOutMessage.VIDEO() .mediaId("media_id") .fromUser("fromUser") - .touser("toUser") + .toUser("toUser") .title("title") .description("ddfff") .build(); diff --git a/src/test/java/me/chanjar/weixin/bean/WxXmlOutIVoiceMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java similarity index 81% rename from src/test/java/me/chanjar/weixin/bean/WxXmlOutIVoiceMessageTest.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java index ea1055ec..fa73a329 100644 --- a/src/test/java/me/chanjar/weixin/bean/WxXmlOutIVoiceMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java @@ -1,15 +1,13 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.cp.bean; -import me.chanjar.weixin.bean.WxXmlOutMessage; -import me.chanjar.weixin.bean.WxXmlOutVoiceMessage; import org.testng.Assert; import org.testng.annotations.Test; @Test -public class WxXmlOutIVoiceMessageTest { +public class WxCpXmlOutVoiceMessageTest { public void test() { - WxXmlOutVoiceMessage m = new WxXmlOutVoiceMessage(); + WxCpXmlOutVoiceMessage m = new WxCpXmlOutVoiceMessage(); m.setMediaId("ddfefesfsdfef"); m.setCreateTime(1122l); m.setFromUserName("from"); @@ -28,7 +26,7 @@ public class WxXmlOutIVoiceMessageTest { } public void testBuild() { - WxXmlOutVoiceMessage m = WxXmlOutMessage.VOICE().mediaId("ddfefesfsdfef").fromUser("from").touser("to").build(); + WxCpXmlOutVoiceMessage m = WxCpXmlOutMessage.VOICE().mediaId("ddfefesfsdfef").fromUser("from").toUser("to").build(); String expected = "" + "" + "" diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java new file mode 100644 index 00000000..0c0d3961 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java @@ -0,0 +1,35 @@ +package me.chanjar.weixin.cp.demo; + +import me.chanjar.weixin.cp.api.WxCpInMemoryConfigStorage; +import org.xml.sax.InputSource; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.InputStream; + +/** + * @author Daniel Qian + */ +@XmlRootElement(name = "xml") +@XmlAccessorType(XmlAccessType.FIELD) +class WxCpDemoInMemoryConfigStorage extends WxCpInMemoryConfigStorage { + + @Override + public String toString() { + return "SimpleWxConfigProvider [appidOrCorpid=" + corpId + ", corpSecret=" + corpSecret + ", accessToken=" + accessToken + + ", expiresIn=" + expiresIn + ", token=" + token + ", aesKey=" + aesKey + "]"; + } + + + public static WxCpDemoInMemoryConfigStorage fromXml(InputStream is) throws JAXBException { + Unmarshaller um = JAXBContext.newInstance(WxCpDemoInMemoryConfigStorage.class).createUnmarshaller(); + InputSource inputSource = new InputSource(is); + inputSource.setEncoding("utf-8"); + return (WxCpDemoInMemoryConfigStorage) um.unmarshal(inputSource); + } + +} diff --git a/src/test/java/me/chanjar/weixin/demo/WxTestServer.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java similarity index 73% rename from src/test/java/me/chanjar/weixin/demo/WxTestServer.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java index e9c6d9d0..b56d1780 100644 --- a/src/test/java/me/chanjar/weixin/demo/WxTestServer.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.demo; +package me.chanjar.weixin.cp.demo; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletHandler; @@ -6,14 +6,14 @@ import org.eclipse.jetty.servlet.ServletHandler; /** * @author Daniel Qian */ -public class WxTestServer { +public class WxCpDemoServer { public static void main(String[] args) throws Exception { Server server = new Server(8080); ServletHandler handler = new ServletHandler(); server.setHandler(handler); - handler.addServletWithMapping(WxTestServlet.class, "/*"); + handler.addServletWithMapping(WxCpDemoServlet.class, "/*"); server.start(); server.join(); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServlet.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServlet.java new file mode 100644 index 00000000..b84d786f --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServlet.java @@ -0,0 +1,99 @@ +package me.chanjar.weixin.cp.demo; + +import me.chanjar.weixin.cp.api.*; +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; +import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; +import org.apache.commons.lang3.StringUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.bind.JAXBException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +/** + * @author Daniel Qian + */ +public class WxCpDemoServlet extends HttpServlet { + + protected WxCpService wxCpService; + protected WxCpConfigStorage wxCpConfigStorage; + protected WxCpMessageRouter wxCpMessageRouter; + + @Override public void init() throws ServletException { + // + super.init(); + try { + InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml"); + WxCpDemoInMemoryConfigStorage config = WxCpDemoInMemoryConfigStorage.fromXml(is1); + + wxCpConfigStorage = config; + wxCpService = new WxCpServiceImpl(); + wxCpService.setWxCpConfigStorage(config); + + WxCpMessageHandler handler = new WxCpMessageHandler() { + @Override public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context) { + WxCpXmlOutTextMessage m = WxCpXmlOutMessage + .TEXT() + .content("测试加密消息") + .fromUser(wxMessage.getToUserName()) + .toUser(wxMessage.getFromUserName()) + .build(); + return m; + } + }; + + wxCpMessageRouter = new WxCpMessageRouter(); + wxCpMessageRouter + .rule() + .async(false) + .content("哈哈") // 拦截内容为“哈哈”的消息 + .handler(handler) + .end(); + + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } + + @Override protected void service(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + String msgSignature = request.getParameter("msg_signature"); + String nonce = request.getParameter("nonce"); + String timestamp = request.getParameter("timestamp"); + String echostr = request.getParameter("echostr"); + + response.setContentType("text/html;charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + if (StringUtils.isNotBlank(echostr)) { + if (!wxCpService.checkSignature(msgSignature, timestamp, nonce, echostr)) { + // 消息签名不正确,说明不是公众平台发过来的消息 + response.getWriter().println("非法请求"); + return; + } + WxCpCryptUtil cryptUtil = new WxCpCryptUtil(wxCpConfigStorage); + String plainText = cryptUtil.decrypt(echostr); + // 说明是一个仅仅用来验证的请求,回显echostr + response.getWriter().println(plainText); + return; + } + + + WxCpXmlMessage inMessage = WxCpXmlMessage.fromEncryptedXml(request.getInputStream(), wxCpConfigStorage, timestamp, nonce, msgSignature); + + WxCpXmlOutMessage outMessage = wxCpMessageRouter.route(inMessage); + + if (outMessage != null) { + response.getWriter().write(outMessage.toEncryptedXml(wxCpConfigStorage)); + } + + return; + } + +} diff --git a/src/test/resources/mm.jpeg b/weixin-java-cp/src/test/resources/mm.jpeg similarity index 100% rename from src/test/resources/mm.jpeg rename to weixin-java-cp/src/test/resources/mm.jpeg diff --git a/src/test/resources/mm.mp3 b/weixin-java-cp/src/test/resources/mm.mp3 similarity index 100% rename from src/test/resources/mm.mp3 rename to weixin-java-cp/src/test/resources/mm.mp3 diff --git a/src/test/resources/mm.mp4 b/weixin-java-cp/src/test/resources/mm.mp4 similarity index 100% rename from src/test/resources/mm.mp4 rename to weixin-java-cp/src/test/resources/mm.mp4 diff --git a/weixin-java-cp/src/test/resources/test-config.sample.xml b/weixin-java-cp/src/test/resources/test-config.sample.xml new file mode 100644 index 00000000..c30d7e35 --- /dev/null +++ b/weixin-java-cp/src/test/resources/test-config.sample.xml @@ -0,0 +1,12 @@ + + 企业号corpid + 企业号corpsecret + 企业号应用id + 企业号应用Token + 企业号应用EncodingAESKey + 可以不填写 + 可以不填写 + 企业号通讯录里的某个userid + 企业号通讯录的某个部门id + 企业号通讯录里的某个tagid + diff --git a/weixin-java-cp/src/test/resources/testng.xml b/weixin-java-cp/src/test/resources/testng.xml new file mode 100644 index 00000000..4cddddcf --- /dev/null +++ b/weixin-java-cp/src/test/resources/testng.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/weixin-java-mp/LICENSE b/weixin-java-mp/LICENSE new file mode 100644 index 00000000..5c304d1a --- /dev/null +++ b/weixin-java-mp/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml new file mode 100644 index 00000000..c2477c3f --- /dev/null +++ b/weixin-java-mp/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + me.chanjar + weixin-java-parent + 1.0.3-SNAPSHOT + + weixin-java-mp + WeiXin Java Tools - MP + 微信公众号Java SDK + + + + me.chanjar + weixin-java-common + ${project.version} + + + junit + junit + test + + + org.testng + testng + 6.8.7 + test + + + org.mockito + mockito-all + 1.9.5 + test + + + com.google.inject + guice + 3.0 + test + + + org.eclipse.jetty + jetty-server + 9.3.0.M0 + test + + + org.eclipse.jetty + jetty-servlet + 9.3.0.M0 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + src/test/resources/testng.xml + + + + + + + diff --git a/src/main/java/me/chanjar/weixin/api/WxConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java similarity index 76% rename from src/main/java/me/chanjar/weixin/api/WxConfigStorage.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java index 57bdcd3b..e90013ff 100644 --- a/src/main/java/me/chanjar/weixin/api/WxConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java @@ -1,13 +1,13 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.mp.api; -import me.chanjar.weixin.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.WxAccessToken; /** * 微信客户端配置存储 * @author chanjarster * */ -public interface WxConfigStorage { +public interface WxMpConfigStorage { public void updateAccessToken(WxAccessToken accessToken); diff --git a/src/main/java/me/chanjar/weixin/api/WxInMemoryConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java similarity index 84% rename from src/main/java/me/chanjar/weixin/api/WxInMemoryConfigStorage.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java index 1fe66b38..0218067b 100644 --- a/src/main/java/me/chanjar/weixin/api/WxInMemoryConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java @@ -1,13 +1,13 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.mp.api; -import me.chanjar.weixin.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.WxAccessToken; /** * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 * @author chanjarster * */ -public class WxInMemoryConfigStorage implements WxConfigStorage { +public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { protected String appId; protected String secret; @@ -17,7 +17,7 @@ public class WxInMemoryConfigStorage implements WxConfigStorage { protected int expiresIn; public void updateAccessToken(WxAccessToken accessToken) { - updateAccessToken(accessToken.getAccess_token(), accessToken.getExpires_in()); + updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); } public void updateAccessToken(String accessToken, int expiresIn) { diff --git a/src/main/java/me/chanjar/weixin/api/WxMessageHandler.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java similarity index 56% rename from src/main/java/me/chanjar/weixin/api/WxMessageHandler.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java index b433f957..e80ff5a1 100644 --- a/src/main/java/me/chanjar/weixin/api/WxMessageHandler.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java @@ -1,16 +1,16 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.mp.api; -import java.util.Map; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; -import me.chanjar.weixin.bean.WxXmlMessage; -import me.chanjar.weixin.bean.WxXmlOutMessage; +import java.util.Map; /** * 处理微信推送消息的处理器接口 * @author chanjarster * */ -public interface WxMessageHandler { +public interface WxMpMessageHandler { /** * @@ -18,6 +18,6 @@ public interface WxMessageHandler { * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 * @return xml格式的消息,如果在异步规则里处理的话,可以返回null */ - public WxXmlOutMessage handle(WxXmlMessage wxMessage, Map context); + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context); } diff --git a/src/main/java/me/chanjar/weixin/api/WxMessageInterceptor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageInterceptor.java similarity index 60% rename from src/main/java/me/chanjar/weixin/api/WxMessageInterceptor.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageInterceptor.java index ff4e659c..901defea 100644 --- a/src/main/java/me/chanjar/weixin/api/WxMessageInterceptor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageInterceptor.java @@ -1,16 +1,15 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.mp.api; -import java.util.Map; - -import me.chanjar.weixin.bean.WxXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import java.util.Map; /** * 微信消息拦截器,可以用来做验证 * @author qianjia * */ -public interface WxMessageInterceptor { +public interface WxMpMessageInterceptor { /** * 拦截微信消息 @@ -18,6 +17,6 @@ public interface WxMessageInterceptor { * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 * @return true代表OK,false代表不OK */ - public boolean intercept(WxXmlMessage wxMessage, Map context); + public boolean intercept(WxMpXmlMessage wxMessage, Map context); } diff --git a/src/main/java/me/chanjar/weixin/api/WxMessageRouter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java similarity index 79% rename from src/main/java/me/chanjar/weixin/api/WxMessageRouter.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java index 2a651596..f49cafe6 100644 --- a/src/main/java/me/chanjar/weixin/api/WxMessageRouter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java @@ -1,4 +1,7 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; import java.util.ArrayList; import java.util.HashMap; @@ -8,9 +11,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.regex.Pattern; -import me.chanjar.weixin.bean.WxXmlMessage; -import me.chanjar.weixin.bean.WxXmlOutMessage; - /** *
  * 微信消息路由器,通过代码化的配置,把来自微信的消息交给handler处理
@@ -21,7 +21,7 @@ import me.chanjar.weixin.bean.WxXmlOutMessage;
  * 3. 规则的结束必须用{@link Rule#end()}或者{@link Rule#next()},否则不会生效
  * 
  * 使用方法:
- * WxMessageRouter router = new WxMessageRouter();
+ * WxMpMessageRouter router = new WxMpMessageRouter();
  * router
  *   .rule()
  *       .msgType("MSG_TYPE").event("EVENT").eventKey("EVENT_KEY").content("CONTENT")
@@ -39,7 +39,7 @@ import me.chanjar.weixin.bean.WxXmlOutMessage;
  * @author qianjia
  *
  */
-public class WxMessageRouter {
+public class WxMpMessageRouter {
   
   private final List rules = new ArrayList();
 
@@ -57,7 +57,7 @@ public class WxMessageRouter {
    * 处理微信消息
    * @param wxMessage
    */
-  public WxXmlOutMessage route(final WxXmlMessage wxMessage) {
+  public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage) {
     final List matchRules = new ArrayList();
     // 收集匹配的规则
     for (final Rule rule : rules) {
@@ -86,7 +86,7 @@ public class WxMessageRouter {
       return null;
     }
     
-    WxXmlOutMessage res = null;
+    WxMpXmlOutMessage res = null;
     for (final Rule rule : matchRules) {
       // 返回最后一个匹配规则的结果
       res = rule.service(wxMessage);
@@ -99,7 +99,7 @@ public class WxMessageRouter {
   
   public static class Rule {
     
-    private final WxMessageRouter routerBuilder;
+    private final WxMpMessageRouter routerBuilder;
 
     private boolean async = true;
     
@@ -115,11 +115,11 @@ public class WxMessageRouter {
     
     private boolean reEnter = false;
     
-    private List handlers = new ArrayList();
+    private List handlers = new ArrayList();
     
-    private List interceptors = new ArrayList();
+    private List interceptors = new ArrayList();
     
-    protected Rule(WxMessageRouter routerBuilder) {
+    protected Rule(WxMpMessageRouter routerBuilder) {
       this.routerBuilder = routerBuilder;
     }
     
@@ -188,8 +188,8 @@ public class WxMessageRouter {
      * @param interceptor
      * @return
      */
-    public Rule interceptor(WxMessageInterceptor interceptor) {
-      return interceptor(interceptor, (WxMessageInterceptor[]) null);
+    public Rule interceptor(WxMpMessageInterceptor interceptor) {
+      return interceptor(interceptor, (WxMpMessageInterceptor[]) null);
     }
     
     /**
@@ -198,10 +198,10 @@ public class WxMessageRouter {
      * @param otherInterceptors
      * @return
      */
-    public Rule interceptor(WxMessageInterceptor interceptor, WxMessageInterceptor... otherInterceptors) {
+    public Rule interceptor(WxMpMessageInterceptor interceptor, WxMpMessageInterceptor... otherInterceptors) {
       this.interceptors.add(interceptor);
       if (otherInterceptors != null && otherInterceptors.length > 0) {
-        for (WxMessageInterceptor i : otherInterceptors) {
+        for (WxMpMessageInterceptor i : otherInterceptors) {
           this.interceptors.add(i);
         }
       }
@@ -213,8 +213,8 @@ public class WxMessageRouter {
      * @param handler
      * @return
      */
-    public Rule handler(WxMessageHandler handler) {
-      return handler(handler, (WxMessageHandler[]) null);
+    public Rule handler(WxMpMessageHandler handler) {
+      return handler(handler, (WxMpMessageHandler[]) null);
     }
     
     /**
@@ -223,10 +223,10 @@ public class WxMessageRouter {
      * @param otherHandlers
      * @return
      */
-    public Rule handler(WxMessageHandler handler, WxMessageHandler... otherHandlers) {
+    public Rule handler(WxMpMessageHandler handler, WxMpMessageHandler... otherHandlers) {
       this.handlers.add(handler);
       if (otherHandlers != null && otherHandlers.length > 0) {
-        for (WxMessageHandler i : otherHandlers) {
+        for (WxMpMessageHandler i : otherHandlers) {
           this.handlers.add(i);
         }
       }
@@ -237,7 +237,7 @@ public class WxMessageRouter {
      * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则
      * @return
      */
-    public WxMessageRouter end() {
+    public WxMpMessageRouter end() {
       this.routerBuilder.rules.add(this);
       return this.routerBuilder;
     }
@@ -246,12 +246,12 @@ public class WxMessageRouter {
      * 规则结束,但是消息还会进入其他规则
      * @return
      */
-    public WxMessageRouter next() {
+    public WxMpMessageRouter next() {
       this.reEnter = true;
       return end();
     }
     
-    protected boolean test(WxXmlMessage wxMessage) {
+    protected boolean test(WxMpXmlMessage wxMessage) {
       return 
           (this.msgType == null || this.msgType.equals(wxMessage.getMsgType()))
           &&
@@ -270,18 +270,18 @@ public class WxMessageRouter {
      * @param wxMessage
      * @return true 代表继续执行别的router,false 代表停止执行别的router
      */
-    protected WxXmlOutMessage service(WxXmlMessage wxMessage) {
+    protected WxMpXmlOutMessage service(WxMpXmlMessage wxMessage) {
       Map context = new HashMap();
       // 如果拦截器不通过
-      for (WxMessageInterceptor interceptor : this.interceptors) {
+      for (WxMpMessageInterceptor interceptor : this.interceptors) {
         if (!interceptor.intercept(wxMessage, context)) {
           return null;
         }
       }
       
       // 交给handler处理
-      WxXmlOutMessage res = null;
-      for (WxMessageHandler handler : this.handlers) {
+      WxMpXmlOutMessage res = null;
+      for (WxMpMessageHandler handler : this.handlers) {
         // 返回最后handler的结果
         res = handler.handle(wxMessage, context);
       }
diff --git a/src/main/java/me/chanjar/weixin/api/WxService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
similarity index 77%
rename from src/main/java/me/chanjar/weixin/api/WxService.java
rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
index c5db88bc..4b3a20fc 100644
--- a/src/main/java/me/chanjar/weixin/api/WxService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
@@ -1,29 +1,20 @@
-package me.chanjar.weixin.api;
+package me.chanjar.weixin.mp.api;
+
+import me.chanjar.weixin.common.bean.WxMenu;
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.mp.bean.*;
+import me.chanjar.weixin.mp.bean.result.*;
+import me.chanjar.weixin.common.exception.WxErrorException;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.List;
 
-import me.chanjar.weixin.bean.WxCustomMessage;
-import me.chanjar.weixin.bean.WxGroup;
-import me.chanjar.weixin.bean.WxMassGroupMessage;
-import me.chanjar.weixin.bean.WxMassNews;
-import me.chanjar.weixin.bean.WxMassOpenIdsMessage;
-import me.chanjar.weixin.bean.WxMassVideo;
-import me.chanjar.weixin.bean.WxMenu;
-import me.chanjar.weixin.bean.result.WxMassSendResult;
-import me.chanjar.weixin.bean.result.WxMassUploadResult;
-import me.chanjar.weixin.bean.result.WxMediaUploadResult;
-import me.chanjar.weixin.bean.result.WxQrCodeTicket;
-import me.chanjar.weixin.bean.result.WxUser;
-import me.chanjar.weixin.bean.result.WxUserList;
-import me.chanjar.weixin.exception.WxErrorException;
-
 /**
  * 微信API的Service
  */
-public interface WxService {
+public interface WxMpService {
   
   /**
    * 
@@ -48,7 +39,7 @@ public interface WxService {
 
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token
    * 
- * @throws WxErrorException + * @throws me.chanjar.weixin.common.exception.WxErrorException */ public void accessTokenRefresh() throws WxErrorException; @@ -64,8 +55,8 @@ public interface WxService { * * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件 *
- * @param mediaType 媒体类型, 请看{@link WxConsts} - * @param fileType 文件类型,请看{@link WxConsts} + * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} + * @param fileType 文件类型,请看{@link me.chanjar.weixin.common.api.WxConsts} * @param inputStream 输入流 * @throws WxErrorException */ @@ -99,7 +90,7 @@ public interface WxService { * @param message * @throws WxErrorException */ - public void customMessageSend(WxCustomMessage message) throws WxErrorException; + public void customMessageSend(WxMpCustomMessage message) throws WxErrorException; /** *
@@ -109,10 +100,10 @@ public interface WxService {
    * 
* @param news * @throws WxErrorException - * @see #massGroupMessageSend(WxMassGroupMessage) - * @see #massOpenIdsMessageSend(WxMassOpenIdsMessage) + * @see #massGroupMessageSend(me.chanjar.weixin.mp.bean.WxMpMassGroupMessage) + * @see #massOpenIdsMessageSend(me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage) */ - public WxMassUploadResult massNewsUpload(WxMassNews news) throws WxErrorException; + public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException; /** *
@@ -121,36 +112,36 @@ public interface WxService {
    * 
* @return * @throws WxErrorException - * @see #massGroupMessageSend(WxMassGroupMessage) - * @see #massOpenIdsMessageSend(WxMassOpenIdsMessage) + * @see #massGroupMessageSend(me.chanjar.weixin.mp.bean.WxMpMassGroupMessage) + * @see #massOpenIdsMessageSend(me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage) */ - public WxMassUploadResult massVideoUpload(WxMassVideo video) throws WxErrorException; + public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException; /** *
    * 分组群发消息
-   * 如果发送图文消息,必须先使用 {@link #massNewsUpload(WxMassNews)} 获得media_id,然后再发送
-   * 如果发送视频消息,必须先使用 {@link #massVideoUpload(WxMassVideo)} 获得media_id,然后再发送
+   * 如果发送图文消息,必须先使用 {@link #massNewsUpload(me.chanjar.weixin.mp.bean.WxMpMassNews)} 获得media_id,然后再发送
+   * 如果发送视频消息,必须先使用 {@link #massVideoUpload(me.chanjar.weixin.mp.bean.WxMpMassVideo)} 获得media_id,然后再发送
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口
    * 
* @param message * @throws WxErrorException * @return */ - public WxMassSendResult massGroupMessageSend(WxMassGroupMessage message) throws WxErrorException; + public WxMpMassSendResult massGroupMessageSend(WxMpMassGroupMessage message) throws WxErrorException; /** *
    * 按openId列表群发消息
-   * 如果发送图文消息,必须先使用 {@link #massNewsUpload(WxMassNews)} 获得media_id,然后再发送
-   * 如果发送视频消息,必须先使用 {@link #massVideoUpload(WxMassVideo)} 获得media_id,然后再发送
+   * 如果发送图文消息,必须先使用 {@link #massNewsUpload(me.chanjar.weixin.mp.bean.WxMpMassNews)} 获得media_id,然后再发送
+   * 如果发送视频消息,必须先使用 {@link #massVideoUpload(me.chanjar.weixin.mp.bean.WxMpMassVideo)} 获得media_id,然后再发送
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口
    * 
* @param message * @return * @throws WxErrorException */ - public WxMassSendResult massOpenIdsMessageSend(WxMassOpenIdsMessage message) throws WxErrorException; + public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException; /** *
@@ -190,7 +181,7 @@ public interface WxService {
    * @param name 分组名字(30个字符以内) 
    * @throws WxErrorException
    */
-  public WxGroup groupCreate(String name) throws WxErrorException;
+  public WxMpGroup groupCreate(String name) throws WxErrorException;
   
   /**
    * 
@@ -200,7 +191,7 @@ public interface WxService {
    * @return
    * @throws WxErrorException
    */
-  public List groupGet() throws WxErrorException;
+  public List groupGet() throws WxErrorException;
   
   /**
    * 
@@ -222,7 +213,7 @@ public interface WxService {
    * @param group 要更新的group,group的id,name必须设置 
    * @throws WxErrorException
    */
-  public void groupUpdate(WxGroup group) throws WxErrorException;
+  public void groupUpdate(WxMpGroup group) throws WxErrorException;
   
   /**
    * 
@@ -258,7 +249,7 @@ public interface WxService {
    * @return
    * @throws WxErrorException
    */
-  public WxUser userInfo(String openid, String lang) throws WxErrorException;
+  public WxMpUser userInfo(String openid, String lang) throws WxErrorException;
 
   /**
    * 
@@ -269,7 +260,7 @@ public interface WxService {
    * @return
    * @throws WxErrorException
    */
-  public WxUserList userList(String next_openid) throws WxErrorException;
+  public WxMpUserList userList(String next_openid) throws WxErrorException;
 
   /**
    * 
@@ -281,7 +272,7 @@ public interface WxService {
    * @return
    * @throws WxErrorException
    */
-  public WxQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException;
+  public WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException;
 
   /**
    * 
@@ -292,7 +283,7 @@ public interface WxService {
    * @return
    * @throws WxErrorException
    */
-  public WxQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException;
+  public WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException;
 
   /**
    * 
@@ -303,7 +294,7 @@ public interface WxService {
    * @return
    * @throws WxErrorException
    */
-  public File qrCodePicture(WxQrCodeTicket ticket) throws WxErrorException;
+  public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException;
 
   /**
    * 
@@ -317,8 +308,8 @@ public interface WxService {
   public String shortUrl(String long_url) throws WxErrorException;
   
   /**
-   * 注入 {@link WxConfigStorage} 的实现
+   * 注入 {@link WxMpConfigStorage} 的实现
    * @param wxConfigProvider
    */
-  public void setWxConfigStorage(WxConfigStorage wxConfigProvider);
+  public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider);
 }
diff --git a/src/main/java/me/chanjar/weixin/api/WxServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java
similarity index 74%
rename from src/main/java/me/chanjar/weixin/api/WxServiceImpl.java
rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java
index 90ed8eac..c40af33d 100644
--- a/src/main/java/me/chanjar/weixin/api/WxServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java
@@ -1,18 +1,23 @@
-package me.chanjar.weixin.api;
+package me.chanjar.weixin.mp.api;
 
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringReader;
-import java.security.MessageDigest;
-import java.util.Arrays;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import me.chanjar.weixin.bean.WxCustomMessage;
-import me.chanjar.weixin.util.crypto.SHA1;
-import me.chanjar.weixin.util.json.GsonHelper;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.internal.Streams;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+import me.chanjar.weixin.common.bean.WxAccessToken;
+import me.chanjar.weixin.common.bean.WxMenu;
+import me.chanjar.weixin.common.bean.result.WxError;
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.exception.WxErrorException;
+import me.chanjar.weixin.common.util.crypto.SHA1;
+import me.chanjar.weixin.common.util.fs.FileUtils;
+import me.chanjar.weixin.common.util.http.*;
+import me.chanjar.weixin.common.util.json.GsonHelper;
+import me.chanjar.weixin.mp.bean.*;
+import me.chanjar.weixin.mp.bean.result.*;
+import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.client.ClientProtocolException;
 import org.apache.http.client.methods.CloseableHttpResponse;
@@ -21,37 +26,15 @@ import org.apache.http.impl.client.BasicResponseHandler;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 
-import me.chanjar.weixin.bean.WxAccessToken;
-import me.chanjar.weixin.bean.WxGroup;
-import me.chanjar.weixin.bean.WxMassGroupMessage;
-import me.chanjar.weixin.bean.WxMassNews;
-import me.chanjar.weixin.bean.WxMassOpenIdsMessage;
-import me.chanjar.weixin.bean.WxMassVideo;
-import me.chanjar.weixin.bean.WxMenu;
-import me.chanjar.weixin.bean.result.WxError;
-import me.chanjar.weixin.bean.result.WxMassSendResult;
-import me.chanjar.weixin.bean.result.WxMassUploadResult;
-import me.chanjar.weixin.bean.result.WxMediaUploadResult;
-import me.chanjar.weixin.bean.result.WxQrCodeTicket;
-import me.chanjar.weixin.bean.result.WxUser;
-import me.chanjar.weixin.bean.result.WxUserList;
-import me.chanjar.weixin.exception.WxErrorException;
-import me.chanjar.weixin.util.fs.FileUtils;
-import me.chanjar.weixin.util.http.MediaDownloadRequestExecutor;
-import me.chanjar.weixin.util.http.MediaUploadRequestExecutor;
-import me.chanjar.weixin.util.http.QrCodeRequestExecutor;
-import me.chanjar.weixin.util.http.RequestExecutor;
-import me.chanjar.weixin.util.http.SimpleGetRequestExecutor;
-import me.chanjar.weixin.util.http.SimplePostRequestExecutor;
-import me.chanjar.weixin.util.json.WxGsonBuilder;
-
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.internal.Streams;
-import com.google.gson.reflect.TypeToken;
-import com.google.gson.stream.JsonReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
 
-public class WxServiceImpl implements WxService {
+public class WxMpServiceImpl implements WxMpService {
 
   /**
    * 全局的是否正在刷新Access Token的flag
@@ -62,13 +45,13 @@ public class WxServiceImpl implements WxService {
   
   protected static final CloseableHttpClient httpclient = HttpClients.createDefault();
   
-  protected WxConfigStorage wxConfigStorage;
+  protected WxMpConfigStorage wxMpConfigStorage;
   
   protected final ThreadLocal retryTimes = new ThreadLocal();
 
   public boolean checkSignature(String timestamp, String nonce, String signature) {
     try {
-      return SHA1.gen(wxConfigStorage.getToken(), timestamp, nonce).equals(signature);
+      return SHA1.gen(wxMpConfigStorage.getToken(), timestamp, nonce).equals(signature);
     } catch (Exception e) {
       return false;
     }
@@ -78,19 +61,19 @@ public class WxServiceImpl implements WxService {
     if (!GLOBAL_ACCESS_TOKEN_REFRESH_FLAG.getAndSet(true)) {
       try {
         String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"
-            + "&appid=" + wxConfigStorage.getAppId() 
-            + "&secret=" + wxConfigStorage.getSecret()
+            + "&appid=" + wxMpConfigStorage.getAppId()
+            + "&secret=" + wxMpConfigStorage.getSecret()
             ;
         try {
           HttpGet httpGet = new HttpGet(url);
           CloseableHttpResponse response = httpclient.execute(httpGet);
           String resultContent = new BasicResponseHandler().handleResponse(response);
           WxError error = WxError.fromJson(resultContent);
-          if (error.getErrcode() != 0) {
+          if (error.getErrorCode() != 0) {
             throw new WxErrorException(error);
           }
           WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
-          wxConfigStorage.updateAccessToken(accessToken.getAccess_token(), accessToken.getExpires_in());
+          wxMpConfigStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
         } catch (ClientProtocolException e) {
           throw new RuntimeException(e);
         } catch (IOException e) {
@@ -111,7 +94,7 @@ public class WxServiceImpl implements WxService {
     }
   }
   
-  public void customMessageSend(WxCustomMessage message) throws WxErrorException {
+  public void customMessageSend(WxMpCustomMessage message) throws WxErrorException {
     String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send";
     execute(new SimplePostRequestExecutor(), url, message.toJson());
   }
@@ -133,7 +116,7 @@ public class WxServiceImpl implements WxService {
       return WxMenu.fromJson(resultContent);
     } catch (WxErrorException e) {
       // 46003 不存在的菜单数据
-      if (e.getError().getErrcode() == 46003) {
+      if (e.getError().getErrorCode() == 46003) {
         return null;
       }
       throw e;
@@ -154,31 +137,31 @@ public class WxServiceImpl implements WxService {
     return execute(new MediaDownloadRequestExecutor(), url, "media_id=" + media_id);
   }
 
-  public WxMassUploadResult massNewsUpload(WxMassNews news) throws WxErrorException {
+  public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException {
     String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews";
     String responseContent = execute(new SimplePostRequestExecutor(), url, news.toJson());
-    return WxMassUploadResult.fromJson(responseContent);
+    return WxMpMassUploadResult.fromJson(responseContent);
   }
   
-  public WxMassUploadResult massVideoUpload(WxMassVideo video) throws WxErrorException {
+  public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException {
     String url = "http://file.api.weixin.qq.com/cgi-bin/media/uploadvideo";
     String responseContent = execute(new SimplePostRequestExecutor(), url, video.toJson());
-    return WxMassUploadResult.fromJson(responseContent);
+    return WxMpMassUploadResult.fromJson(responseContent);
   }
   
-  public WxMassSendResult massGroupMessageSend(WxMassGroupMessage message) throws WxErrorException {
+  public WxMpMassSendResult massGroupMessageSend(WxMpMassGroupMessage message) throws WxErrorException {
     String url = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall";
     String responseContent = execute(new SimplePostRequestExecutor(), url, message.toJson());
-    return WxMassSendResult.fromJson(responseContent);
+    return WxMpMassSendResult.fromJson(responseContent);
   }
 
-  public WxMassSendResult massOpenIdsMessageSend(WxMassOpenIdsMessage message) throws WxErrorException {
+  public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException {
     String url = "https://api.weixin.qq.com/cgi-bin/message/mass/send";
     String responseContent = execute(new SimplePostRequestExecutor(), url, message.toJson());
-    return WxMassSendResult.fromJson(responseContent);
+    return WxMpMassSendResult.fromJson(responseContent);
   }
   
-  public WxGroup groupCreate(String name) throws WxErrorException {
+  public WxMpGroup groupCreate(String name) throws WxErrorException {
     String url = "https://api.weixin.qq.com/cgi-bin/groups/create";
     JsonObject json = new JsonObject();
     JsonObject groupJson = new JsonObject();
@@ -189,10 +172,10 @@ public class WxServiceImpl implements WxService {
         new SimplePostRequestExecutor(), 
         url, 
         json.toString());
-    return WxGroup.fromJson(responseContent);
+    return WxMpGroup.fromJson(responseContent);
   }
 
-  public List groupGet() throws WxErrorException {
+  public List groupGet() throws WxErrorException {
     String url = "https://api.weixin.qq.com/cgi-bin/groups/get";
     String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
     /*
@@ -200,7 +183,7 @@ public class WxServiceImpl implements WxService {
      * 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] }
      */
     JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
-    return WxGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("groups"), new TypeToken>(){}.getType());
+    return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("groups"), new TypeToken>(){}.getType());
   }
   
   public long userGetGroup(String openid) throws WxErrorException {
@@ -212,7 +195,7 @@ public class WxServiceImpl implements WxService {
     return GsonHelper.getAsLong(tmpJsonElement.getAsJsonObject().get("groupid"));
   }
   
-  public void groupUpdate(WxGroup group) throws WxErrorException {
+  public void groupUpdate(WxMpGroup group) throws WxErrorException {
     String url = "https://api.weixin.qq.com/cgi-bin/groups/update";
     execute(new SimplePostRequestExecutor(), url, group.toJson());
   }
@@ -233,20 +216,20 @@ public class WxServiceImpl implements WxService {
     execute(new SimplePostRequestExecutor(), url, json.toString());
   }
   
-  public WxUser userInfo(String openid, String lang) throws WxErrorException {
+  public WxMpUser userInfo(String openid, String lang) throws WxErrorException {
     String url = "https://api.weixin.qq.com/cgi-bin/user/info";
     lang = lang == null ? "zh_CN" : lang;
     String responseContent = execute(new SimpleGetRequestExecutor(), url, "openid=" + openid + "&lang=" + lang);
-    return WxUser.fromJson(responseContent);
+    return WxMpUser.fromJson(responseContent);
   }
   
-  public WxUserList userList(String next_openid) throws WxErrorException {
+  public WxMpUserList userList(String next_openid) throws WxErrorException {
     String url = "https://api.weixin.qq.com/cgi-bin/user/get";
     String responseContent = execute(new SimpleGetRequestExecutor(), url, next_openid == null ? null : "next_openid=" + next_openid);
-    return WxUserList.fromJson(responseContent);
+    return WxMpUserList.fromJson(responseContent);
   }
   
-  public WxQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException {
+  public WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException {
     String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create";
     JsonObject json = new JsonObject();
     json.addProperty("action_name", "QR_SCENE");
@@ -259,10 +242,10 @@ public class WxServiceImpl implements WxService {
     actionInfo.add("scene", scene);
     json.add("action_info", actionInfo);
     String responseContent = execute(new SimplePostRequestExecutor(), url, json.toString());
-    return WxQrCodeTicket.fromJson(responseContent);
+    return WxMpQrCodeTicket.fromJson(responseContent);
   }
   
-  public WxQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException {
+  public WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException {
     String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create";
     JsonObject json = new JsonObject();
     json.addProperty("action_name", "QR_LIMIT_SCENE");
@@ -272,10 +255,10 @@ public class WxServiceImpl implements WxService {
     actionInfo.add("scene", scene);
     json.add("action_info", actionInfo);
     String responseContent = execute(new SimplePostRequestExecutor(), url, json.toString());
-    return WxQrCodeTicket.fromJson(responseContent);
+    return WxMpQrCodeTicket.fromJson(responseContent);
   }
   
-  public File qrCodePicture(WxQrCodeTicket ticket) throws WxErrorException {
+  public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException {
     String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode";
     return execute(new QrCodeRequestExecutor(), url, ticket);
   }
@@ -299,10 +282,10 @@ public class WxServiceImpl implements WxService {
    * @throws WxErrorException
    */
   public  T execute(RequestExecutor executor, String uri, E data) throws WxErrorException {
-    if (StringUtils.isBlank(wxConfigStorage.getAccessToken())) {
+    if (StringUtils.isBlank(wxMpConfigStorage.getAccessToken())) {
       accessTokenRefresh();
     }
-    String accessToken = wxConfigStorage.getAccessToken();
+    String accessToken = wxMpConfigStorage.getAccessToken();
     
     String uriWithAccessToken = uri;
     uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken;
@@ -316,14 +299,14 @@ public class WxServiceImpl implements WxService {
        * 40001 获取access_token时AppSecret错误,或者access_token无效
        * 42001 access_token超时
        */
-      if (error.getErrcode() == 42001 || error.getErrcode() == 40001) {
+      if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) {
         accessTokenRefresh();
         return execute(executor, uri, data);
       }
       /**
        * -1 系统繁忙, 1000ms后重试
        */
-      if (error.getErrcode() == -1) {
+      if (error.getErrorCode() == -1) {
         if(retryTimes.get() == null) {
           retryTimes.set(0);
         }
@@ -341,7 +324,7 @@ public class WxServiceImpl implements WxService {
           throw new RuntimeException(e1);
         }
       }
-      if (error.getErrcode() != 0) {
+      if (error.getErrorCode() != 0) {
         throw new WxErrorException(error);
       }
       return null;
@@ -352,8 +335,8 @@ public class WxServiceImpl implements WxService {
     }
   }
   
-  public void setWxConfigStorage(WxConfigStorage wxConfigProvider) {
-    this.wxConfigStorage = wxConfigProvider;
+  public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) {
+    this.wxMpConfigStorage = wxConfigProvider;
   }
 
 }
diff --git a/src/main/java/me/chanjar/weixin/bean/WxCustomMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCustomMessage.java
similarity index 54%
rename from src/main/java/me/chanjar/weixin/bean/WxCustomMessage.java
rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCustomMessage.java
index 48dd7220..dc3d3baa 100644
--- a/src/main/java/me/chanjar/weixin/bean/WxCustomMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCustomMessage.java
@@ -1,59 +1,53 @@
-package me.chanjar.weixin.bean;
+package me.chanjar.weixin.mp.bean;
+
+import me.chanjar.weixin.mp.bean.custombuilder.*;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import me.chanjar.weixin.api.WxConsts;
-import me.chanjar.weixin.bean.custombuilder.ImageBuilder;
-import me.chanjar.weixin.bean.custombuilder.MusicBuilder;
-import me.chanjar.weixin.bean.custombuilder.NewsBuilder;
-import me.chanjar.weixin.bean.custombuilder.TextBuilder;
-import me.chanjar.weixin.bean.custombuilder.VideoBuilder;
-import me.chanjar.weixin.bean.custombuilder.VoiceBuilder;
-import me.chanjar.weixin.util.json.WxGsonBuilder;
-
 /**
  * 客服消息
  * @author chanjarster
  *
  */
-public class WxCustomMessage {
+public class WxMpCustomMessage {
 
-  private String touser;
-  private String msgtype;
+  private String toUser;
+  private String msgType;
   private String content;
-  private String media_id;
-  private String thumb_media_id;
+  private String mediaId;
+  private String thumbMediaId;
   private String title;
   private String description;
-  private String musicurl;
-  private String hqmusicurl;
+  private String musicUrl;
+  private String hqMusicUrl;
   private List articles = new ArrayList();
   
-  public String getTouser() {
-    return touser;
+  public String getToUser() {
+    return toUser;
   }
-  public void setTouser(String touser) {
-    this.touser = touser;
+  public void setToUser(String toUser) {
+    this.toUser = toUser;
   }
-  public String getMsgtype() {
-    return msgtype;
+  public String getMsgType() {
+    return msgType;
   }
   
   /**
    * 
    * 请使用
-   * {@link WxConsts#CUSTOM_MSG_TEXT}
-   * {@link WxConsts#CUSTOM_MSG_IMAGE}
-   * {@link WxConsts#CUSTOM_MSG_VOICE}
-   * {@link WxConsts#CUSTOM_MSG_MUSIC}
-   * {@link WxConsts#CUSTOM_MSG_VIDEO}
-   * {@link WxConsts#CUSTOM_MSG_NEWS}
+   * {@link me.chanjar.weixin.common.api.WxConsts#CUSTOM_MSG_TEXT}
+   * {@link me.chanjar.weixin.common.api.WxConsts#CUSTOM_MSG_IMAGE}
+   * {@link me.chanjar.weixin.common.api.WxConsts#CUSTOM_MSG_VOICE}
+   * {@link me.chanjar.weixin.common.api.WxConsts#CUSTOM_MSG_MUSIC}
+   * {@link me.chanjar.weixin.common.api.WxConsts#CUSTOM_MSG_VIDEO}
+   * {@link me.chanjar.weixin.common.api.WxConsts#CUSTOM_MSG_NEWS}
    * 
- * @param msgtype + * @param msgType */ - public void setMsgtype(String msgtype) { - this.msgtype = msgtype; + public void setMsgType(String msgType) { + this.msgType = msgType; } public String getContent() { return content; @@ -61,17 +55,17 @@ public class WxCustomMessage { public void setContent(String content) { this.content = content; } - public String getMedia_id() { - return media_id; + public String getMediaId() { + return mediaId; } - public void setMedia_id(String media_id) { - this.media_id = media_id; + public void setMediaId(String mediaId) { + this.mediaId = mediaId; } - public String getThumb_media_id() { - return thumb_media_id; + public String getThumbMediaId() { + return thumbMediaId; } - public void setThumb_media_id(String thumb_media_id) { - this.thumb_media_id = thumb_media_id; + public void setThumbMediaId(String thumbMediaId) { + this.thumbMediaId = thumbMediaId; } public String getTitle() { return title; @@ -85,17 +79,17 @@ public class WxCustomMessage { public void setDescription(String description) { this.description = description; } - public String getMusicurl() { - return musicurl; + public String getMusicUrl() { + return musicUrl; } - public void setMusicurl(String musicurl) { - this.musicurl = musicurl; + public void setMusicUrl(String musicUrl) { + this.musicUrl = musicUrl; } - public String getHqmusicurl() { - return hqmusicurl; + public String getHqMusicUrl() { + return hqMusicUrl; } - public void setHqmusicurl(String hqmusicurl) { - this.hqmusicurl = hqmusicurl; + public void setHqMusicUrl(String hqMusicUrl) { + this.hqMusicUrl = hqMusicUrl; } public List getArticles() { return articles; @@ -105,7 +99,7 @@ public class WxCustomMessage { } public String toJson() { - return WxGsonBuilder.INSTANCE.create().toJson(this); + return WxMpGsonBuilder.INSTANCE.create().toJson(this); } public static class WxArticle { @@ -113,7 +107,7 @@ public class WxCustomMessage { private String title; private String description; private String url; - private String picurl; + private String picUrl; public String getTitle() { return title; @@ -133,11 +127,11 @@ public class WxCustomMessage { public void setUrl(String url) { this.url = url; } - public String getPicurl() { - return picurl; + public String getPicUrl() { + return picUrl; } - public void setPicurl(String picurl) { - this.picurl = picurl; + public void setPicUrl(String picUrl) { + this.picUrl = picUrl; } } diff --git a/src/main/java/me/chanjar/weixin/bean/WxGroup.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpGroup.java similarity index 59% rename from src/main/java/me/chanjar/weixin/bean/WxGroup.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpGroup.java index 0174f562..cfa5fcb6 100644 --- a/src/main/java/me/chanjar/weixin/bean/WxGroup.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpGroup.java @@ -1,13 +1,13 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.mp.bean; -import me.chanjar.weixin.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** * 微信用户分组 * @author chanjarster * */ -public class WxGroup { +public class WxMpGroup { private long id = -1; private String name; @@ -31,16 +31,16 @@ public class WxGroup { this.count = count; } - public static WxGroup fromJson(String json) { - return WxGsonBuilder.create().fromJson(json, WxGroup.class); + public static WxMpGroup fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpGroup.class); } public String toJson() { - return WxGsonBuilder.create().toJson(this); + return WxMpGsonBuilder.create().toJson(this); } @Override public String toString() { - return "WxGroup [id=" + id + ", name=" + name + ", count=" + count + "]"; + return "WxMpGroup [id=" + id + ", name=" + name + ", count=" + count + "]"; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassGroupMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassGroupMessage.java new file mode 100644 index 00000000..c8e859c0 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassGroupMessage.java @@ -0,0 +1,69 @@ +package me.chanjar.weixin.mp.bean; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +/** + * 分组群发的消息 + * + * @author chanjarster + */ +public class WxMpMassGroupMessage { + + private long groupId; + private String msgtype; + private String content; + private String mediaId; + + public WxMpMassGroupMessage() { + super(); + } + + public String getMsgtype() { + return msgtype; + } + + /** + *
+   * 请使用
+   * {@link me.chanjar.weixin.common.api.WxConsts#MASS_MSG_IMAGE}
+   * {@link me.chanjar.weixin.common.api.WxConsts#MASS_MSG_NEWS}
+   * {@link me.chanjar.weixin.common.api.WxConsts#MASS_MSG_TEXT}
+   * {@link me.chanjar.weixin.common.api.WxConsts#MASS_MSG_VIDEO}
+   * {@link me.chanjar.weixin.common.api.WxConsts#MASS_MSG_VOICE}
+   * 如果msgtype和media_id不匹配的话,会返回系统繁忙的错误
+   * 
+ * @param msgtype + */ + public void setMsgtype(String msgtype) { + this.msgtype = msgtype; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public String toJson() { + return WxMpGsonBuilder.INSTANCE.create().toJson(this); + } + + public long getGroupId() { + return groupId; + } + + public void setGroupId(long groupId) { + this.groupId = groupId; + } + +} diff --git a/src/main/java/me/chanjar/weixin/bean/WxMassNews.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java similarity index 56% rename from src/main/java/me/chanjar/weixin/bean/WxMassNews.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java index 262c9adb..f3c67d5a 100644 --- a/src/main/java/me/chanjar/weixin/bean/WxMassNews.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java @@ -1,50 +1,50 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.mp.bean; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; import java.util.ArrayList; import java.util.List; -import me.chanjar.weixin.util.json.WxGsonBuilder; - /** * 群发时用到的图文消息素材 * @author chanjarster * */ -public class WxMassNews { +public class WxMpMassNews { - private List articles = new ArrayList(); + private List articles = new ArrayList(); - public List getArticles() { + public List getArticles() { return articles; } - public void addArticle(WxMassNewsArticle article) { + public void addArticle(WxMpMassNewsArticle article) { this.articles.add(article); } public String toJson() { - return WxGsonBuilder.INSTANCE.create().toJson(this); + return WxMpGsonBuilder.INSTANCE.create().toJson(this); } /** *
    * 群发图文消息article
-   * 1. thumb_media_id  (必填) 图文消息缩略图的media_id,可以在基础支持-上传多媒体文件接口中获得
+   * 1. thumbMediaId  (必填) 图文消息缩略图的media_id,可以在基础支持-上传多媒体文件接口中获得
    * 2. author          图文消息的作者
    * 3. title           (必填) 图文消息的标题
-   * 4. content_source_url 在图文消息页面点击“阅读原文”后的页面链接
+   * 4. contentSourceUrl 在图文消息页面点击“阅读原文”后的页面链接
    * 5. content (必填)  图文消息页面的内容,支持HTML标签
    * 6. digest          图文消息的描述
-   * 7, show_cover_pic  是否显示封面,true为显示,false为不显示
+   * 7, showCoverPic  是否显示封面,true为显示,false为不显示
    * 
* @author chanjarster * */ - public static class WxMassNewsArticle { + public static class WxMpMassNewsArticle { /** * (必填) 图文消息缩略图的media_id,可以在基础支持-上传多媒体文件接口中获得 */ - private String thumb_media_id; + private String thumbMediaId; /** * 图文消息的作者 */ @@ -56,7 +56,7 @@ public class WxMassNews { /** * 在图文消息页面点击“阅读原文”后的页面链接 */ - private String content_source_url; + private String contentSourceUrl; /** * (必填) 图文消息页面的内容,支持HTML标签 */ @@ -68,13 +68,13 @@ public class WxMassNews { /** * 是否显示封面,true为显示,false为不显示 */ - private boolean show_cover_pic; + private boolean showCoverPic; - public String getThumb_media_id() { - return thumb_media_id; + public String getThumbMediaId() { + return thumbMediaId; } - public void setThumb_media_id(String thumb_media_id) { - this.thumb_media_id = thumb_media_id; + public void setThumbMediaId(String thumbMediaId) { + this.thumbMediaId = thumbMediaId; } public String getAuthor() { return author; @@ -88,11 +88,11 @@ public class WxMassNews { public void setTitle(String title) { this.title = title; } - public String getContent_source_url() { - return content_source_url; + public String getContentSourceUrl() { + return contentSourceUrl; } - public void setContent_source_url(String content_source_url) { - this.content_source_url = content_source_url; + public void setContentSourceUrl(String contentSourceUrl) { + this.contentSourceUrl = contentSourceUrl; } public String getContent() { return content; @@ -106,11 +106,11 @@ public class WxMassNews { public void setDigest(String digest) { this.digest = digest; } - public boolean isShow_cover_pic() { - return show_cover_pic; + public boolean isShowCoverPic() { + return showCoverPic; } - public void setShow_cover_pic(boolean show_cover_pic) { - this.show_cover_pic = show_cover_pic; + public void setShowCoverPic(boolean showCoverPic) { + this.showCoverPic = showCoverPic; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java new file mode 100644 index 00000000..b542162b --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java @@ -0,0 +1,79 @@ +package me.chanjar.weixin.mp.bean; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.util.ArrayList; +import java.util.List; + +/** + * OpenId列表群发的消息 + * + * @author chanjarster + */ +public class WxMpMassOpenIdsMessage { + + private List toUsers = new ArrayList(); + private String msgType; + private String content; + private String mediaId; + + public WxMpMassOpenIdsMessage() { + super(); + } + + public String getMsgType() { + return msgType; + } + + /** + *
+   * 请使用
+   * {@link me.chanjar.weixin.common.api.WxConsts#MASS_MSG_IMAGE}
+   * {@link me.chanjar.weixin.common.api.WxConsts#MASS_MSG_NEWS}
+   * {@link me.chanjar.weixin.common.api.WxConsts#MASS_MSG_TEXT}
+   * {@link me.chanjar.weixin.common.api.WxConsts#MASS_MSG_VIDEO}
+   * {@link me.chanjar.weixin.common.api.WxConsts#MASS_MSG_VOICE}
+   * 如果msgtype和media_id不匹配的话,会返回系统繁忙的错误
+   * 
+ * @param msgType + */ + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public String toJson() { + return WxMpGsonBuilder.INSTANCE.create().toJson(this); + } + + /** + * OpenId列表,最多支持10,000个 + * @return + */ + public List getToUsers() { + return toUsers; + } + + /** + * 添加OpenId,最多支持10,000个 + * @param openId + */ + public void addUser(String openId) { + this.toUsers.add(openId); + } +} diff --git a/src/main/java/me/chanjar/weixin/bean/WxMassVideo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassVideo.java similarity index 57% rename from src/main/java/me/chanjar/weixin/bean/WxMassVideo.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassVideo.java index a0522413..3dc6c5d7 100644 --- a/src/main/java/me/chanjar/weixin/bean/WxMassVideo.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassVideo.java @@ -1,15 +1,15 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.mp.bean; -import me.chanjar.weixin.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** * 群发时用到的视频素材 * * @author chanjarster */ -public class WxMassVideo { +public class WxMpMassVideo { - private String media_id; + private String mediaId; private String title; private String description; @@ -29,15 +29,15 @@ public class WxMassVideo { this.description = description; } - public String getMedia_id() { - return media_id; + public String getMediaId() { + return mediaId; } - public void setMedia_id(String media_id) { - this.media_id = media_id; + public void setMediaId(String mediaId) { + this.mediaId = mediaId; } public String toJson() { - return WxGsonBuilder.INSTANCE.create().toJson(this); + return WxMpGsonBuilder.INSTANCE.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMpXmlOutImageMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMpXmlOutImageMessage.java new file mode 100644 index 00000000..1db47004 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMpXmlOutImageMessage.java @@ -0,0 +1,32 @@ +package me.chanjar.weixin.mp.bean; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.util.xml.MediaIdMarshaller; + +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; + +@XmlRootElement(name = "xml") +@XmlAccessorType(XmlAccessType.FIELD) +public class WxMpMpXmlOutImageMessage extends WxMpXmlOutMessage { + + @XmlElement(name="Image") + @XmlJavaTypeAdapter(MediaIdMarshaller.class) + private String mediaId; + + public WxMpMpXmlOutImageMessage() { + this.msgType = WxConsts.XML_MSG_IMAGE; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java new file mode 100644 index 00000000..8ed9e567 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java @@ -0,0 +1,638 @@ +package me.chanjar.weixin.mp.bean; + +import me.chanjar.weixin.common.util.xml.AdapterCDATA; +import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil; +import me.chanjar.weixin.mp.util.xml.XmlTransformer; +import org.apache.commons.io.IOUtils; + +import javax.xml.bind.JAXBException; +import javax.xml.bind.annotation.*; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + *
+ * 微信推送过来的消息,也是同步回复给用户的消息,xml格式
+ * 相关字段的解释看微信开发者文档:
+ * http://mp.weixin.qq.com/wiki/index.php?title=接收普通消息
+ * http://mp.weixin.qq.com/wiki/index.php?title=接收事件推送
+ * http://mp.weixin.qq.com/wiki/index.php?title=接收语音识别结果
+ * 
+ * + * @author chanjarster + */ +@XmlRootElement(name = "xml") +@XmlAccessorType(XmlAccessType.FIELD) +public class WxMpXmlMessage { + + /////////////////////// + // 以下都是微信推送过来的消息的xml的element所对应的属性 + /////////////////////// + + @XmlElement(name = "ToUserName") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String toUserName; + + @XmlElement(name = "FromUserName") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String fromUserName; + + @XmlElement(name = "CreateTime") + private Long createTime; + + @XmlElement(name = "MsgType") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String msgType; + + @XmlElement(name = "Content") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String content; + + @XmlElement(name = "MsgId") + private Long msgId; + + @XmlElement(name = "PicUrl") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String picUrl; + + @XmlElement(name = "MediaId") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String mediaId; + + @XmlElement(name = "Format") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String format; + + @XmlElement(name = "ThumbMediaId") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String thumbMediaId; + + @XmlElement(name = "Location_X") + private Double locationX; + + @XmlElement(name = "Location_Y") + private Double locationY; + + @XmlElement(name = "Scale") + private Double scale; + + @XmlElement(name = "Label") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String label; + + @XmlElement(name = "Title") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String title; + + @XmlElement(name = "Description") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String description; + + @XmlElement(name = "Url") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String url; + + @XmlElement(name = "Event") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String event; + + @XmlElement(name = "EventKey") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String eventKey; + + @XmlElement(name = "Ticket") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String ticket; + + @XmlElement(name = "Latitude") + private Double latitude; + + @XmlElement(name = "Longitude") + private Double longitude; + + @XmlElement(name = "Precision") + private Double precision; + + @XmlElement(name = "Recognition") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String recognition; + + /////////////////////////////////////// + // 群发消息返回的结果 + /////////////////////////////////////// + /** + * 群发的结果 + */ + @XmlElement(name = "Status") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String status; + /** + * group_id下粉丝数;或者openid_list中的粉丝数 + */ + @XmlElement(name = "TotalCount") + private Integer totalCount; + /** + * 过滤(过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超4条的过滤)后,准备发送的粉丝数,原则上,filterCount = sentCount + errorCount + */ + @XmlElement(name = "FilterCount") + private Integer filterCount; + /** + * 发送成功的粉丝数 + */ + @XmlElement(name = "SentCount") + private Integer sentCount; + /** + * 发送失败的粉丝数 + */ + @XmlElement(name = "ErrorCount") + private Integer errorCount; + + @XmlElement(name = "ScanCodeInfo") + private ScanCodeInfo scanCodeInfo = new ScanCodeInfo(); + + @XmlElement(name = "SendPicsInfo") + private SendPicsInfo sendPicsInfo = new SendPicsInfo(); + + @XmlElement(name = "SendLocationInfo") + private SendLocationInfo sendLocationInfo = new SendLocationInfo(); + + public String getToUserName() { + return toUserName; + } + + public void setToUserName(String toUserName) { + this.toUserName = toUserName; + } + + public Long getCreateTime() { + return createTime; + } + + public void setCreateTime(Long createTime) { + this.createTime = createTime; + } + + /** + *
+   * 当接受用户消息时,可能会获得以下值:
+   * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_TEXT}
+   * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_IMAGE}
+   * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_VOICE}
+   * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_VIDEO}
+   * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_LOCATION}
+   * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_LINK}
+   * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_EVENT}
+   * 
+ * + * @return + */ + public String getMsgType() { + return msgType; + } + + /** + *
+   * 当发送消息的时候使用:
+   * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_TEXT}
+   * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_IMAGE}
+   * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_VOICE}
+   * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_VIDEO}
+   * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_NEWS}
+   * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_MUSIC}
+   * 
+ * + * @param msgType + */ + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public Long getMsgId() { + return msgId; + } + + public void setMsgId(Long msgId) { + this.msgId = msgId; + } + + public String getPicUrl() { + return picUrl; + } + + public void setPicUrl(String picUrl) { + this.picUrl = picUrl; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public String getThumbMediaId() { + return thumbMediaId; + } + + public void setThumbMediaId(String thumbMediaId) { + this.thumbMediaId = thumbMediaId; + } + + public Double getLocationX() { + return locationX; + } + + public void setLocationX(Double locationX) { + this.locationX = locationX; + } + + public Double getLocationY() { + return locationY; + } + + public void setLocationY(Double locationY) { + this.locationY = locationY; + } + + public Double getScale() { + return scale; + } + + public void setScale(Double scale) { + this.scale = scale; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getEvent() { + return event; + } + + public void setEvent(String event) { + this.event = event; + } + + public String getEventKey() { + return eventKey; + } + + public void setEventKey(String eventKey) { + this.eventKey = eventKey; + } + + public String getTicket() { + return ticket; + } + + public void setTicket(String ticket) { + this.ticket = ticket; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Double getPrecision() { + return precision; + } + + public void setPrecision(Double precision) { + this.precision = precision; + } + + public String getRecognition() { + return recognition; + } + + public void setRecognition(String recognition) { + this.recognition = recognition; + } + + public String getFromUserName() { + return fromUserName; + } + + public void setFromUserName(String fromUserName) { + this.fromUserName = fromUserName; + } + + public static WxMpXmlMessage fromXml(String xml) { + try { + return XmlTransformer.fromXml(WxMpXmlMessage.class, xml); + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } + + public static WxMpXmlMessage fromXml(InputStream is) { + try { + return XmlTransformer.fromXml(WxMpXmlMessage.class, is); + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } + + /** + * 从加密字符串转换 + * + * @param encryptedXml + * @param wxMpConfigStorage + * @param timestamp + * @param nonce + * @param msgSignature + * @return + */ + public static WxMpXmlMessage fromEncryptedXml( + String encryptedXml, + WxMpConfigStorage wxMpConfigStorage, + String timestamp, String nonce, String msgSignature) { + WxMpCryptUtil cryptUtil = new WxMpCryptUtil(wxMpConfigStorage); + String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml); + return fromXml(plainText); + } + + public static WxMpXmlMessage fromEncryptedXml( + InputStream is, + WxMpConfigStorage wxMpConfigStorage, + String timestamp, String nonce, String msgSignature) { + try { + return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxMpConfigStorage, timestamp, nonce, msgSignature); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Integer getTotalCount() { + return totalCount; + } + + public void setTotalCount(Integer totalCount) { + this.totalCount = totalCount; + } + + public Integer getFilterCount() { + return filterCount; + } + + public void setFilterCount(Integer filterCount) { + this.filterCount = filterCount; + } + + public Integer getSentCount() { + return sentCount; + } + + public void setSentCount(Integer sentCount) { + this.sentCount = sentCount; + } + + public Integer getErrorCount() { + return errorCount; + } + + public void setErrorCount(Integer errorCount) { + this.errorCount = errorCount; + } + + public WxMpXmlMessage.ScanCodeInfo getScanCodeInfo() { + return scanCodeInfo; + } + + public void setScanCodeInfo(WxMpXmlMessage.ScanCodeInfo scanCodeInfo) { + this.scanCodeInfo = scanCodeInfo; + } + + public WxMpXmlMessage.SendPicsInfo getSendPicsInfo() { + return sendPicsInfo; + } + + public void setSendPicsInfo(WxMpXmlMessage.SendPicsInfo sendPicsInfo) { + this.sendPicsInfo = sendPicsInfo; + } + + public WxMpXmlMessage.SendLocationInfo getSendLocationInfo() { + return sendLocationInfo; + } + + public void setSendLocationInfo(WxMpXmlMessage.SendLocationInfo sendLocationInfo) { + this.sendLocationInfo = sendLocationInfo; + } + + @XmlRootElement(name = "ScanCodeInfo") + @XmlAccessorType(XmlAccessType.FIELD) + public static class ScanCodeInfo { + + @XmlElement(name = "ScanType") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String scanType; + + @XmlElement(name = "ScanResult") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String scanResult; + + /** + * 扫描类型,一般是qrcode + * @return + */ + public String getScanType() { + + return scanType; + } + + public void setScanType(String scanType) { + this.scanType = scanType; + } + + /** + * 扫描结果,即二维码对应的字符串信息 + * @return + */ + public String getScanResult() { + return scanResult; + } + + public void setScanResult(String scanResult) { + this.scanResult = scanResult; + } + + } + + @XmlRootElement(name = "SendPicsInfo") + @XmlAccessorType(XmlAccessType.FIELD) + public static class SendPicsInfo { + + @XmlElement(name = "Count") + private Long count; + + @XmlElementWrapper(name="PicList") + @XmlElement(name = "item") + protected final List picList = new ArrayList(); + + public Long getCount() { + return count; + } + + public void setCount(Long count) { + this.count = count; + } + + public List getPicList() { + return picList; + } + + @XmlRootElement(name = "item") + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "WxXmlMessage.SendPicsInfo.Item") + public static class Item { + + @XmlElement(name = "PicMd5Sum") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String PicMd5Sum; + + public String getPicMd5Sum() { + return PicMd5Sum; + } + + public void setPicMd5Sum(String picMd5Sum) { + PicMd5Sum = picMd5Sum; + } + } + } + + @XmlRootElement(name = "SendLocationInfo") + @XmlAccessorType(XmlAccessType.FIELD) + public static class SendLocationInfo { + + @XmlElement(name = "Location_X") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String locationX; + + @XmlElement(name = "Location_Y") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String locationY; + + @XmlElement(name = "Scale") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String scale; + + @XmlElement(name = "Label") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String label; + + @XmlElement(name = "Poiname") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String poiname; + + public String getLocationX() { + return locationX; + } + + public void setLocationX(String locationX) { + this.locationX = locationX; + } + + public String getLocationY() { + return locationY; + } + + public void setLocationY(String locationY) { + this.locationY = locationY; + } + + public String getScale() { + return scale; + } + + public void setScale(String scale) { + this.scale = scale; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getPoiname() { + return poiname; + } + + public void setPoiname(String poiname) { + this.poiname = poiname; + } + } + +} diff --git a/src/main/java/me/chanjar/weixin/bean/WxXmlOutMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMessage.java similarity index 66% rename from src/main/java/me/chanjar/weixin/bean/WxXmlOutMessage.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMessage.java index 1b46901a..b9e4507d 100644 --- a/src/main/java/me/chanjar/weixin/bean/WxXmlOutMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMessage.java @@ -1,4 +1,10 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.mp.bean; + +import me.chanjar.weixin.common.util.xml.AdapterCDATA; +import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.bean.outxmlbuilder.*; +import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil; +import me.chanjar.weixin.mp.util.xml.XmlTransformer; import javax.xml.bind.JAXBException; import javax.xml.bind.annotation.XmlAccessType; @@ -7,66 +13,55 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import me.chanjar.weixin.api.WxConfigStorage; -import me.chanjar.weixin.bean.outxmlbuilder.ImageBuilder; -import me.chanjar.weixin.bean.outxmlbuilder.MusicBuilder; -import me.chanjar.weixin.bean.outxmlbuilder.NewsBuilder; -import me.chanjar.weixin.bean.outxmlbuilder.TextBuilder; -import me.chanjar.weixin.bean.outxmlbuilder.VideoBuilder; -import me.chanjar.weixin.bean.outxmlbuilder.VoiceBuilder; -import me.chanjar.weixin.util.crypto.WxCryptUtil; -import me.chanjar.weixin.util.xml.AdapterCDATA; -import me.chanjar.weixin.util.xml.XmlTransformer; - @XmlRootElement(name = "xml") @XmlAccessorType(XmlAccessType.FIELD) -public class WxXmlOutMessage { +public class WxMpXmlOutMessage { @XmlElement(name="ToUserName") @XmlJavaTypeAdapter(AdapterCDATA.class) - protected String ToUserName; + protected String toUserName; @XmlElement(name="FromUserName") @XmlJavaTypeAdapter(AdapterCDATA.class) - protected String FromUserName; + protected String fromUserName; @XmlElement(name="CreateTime") - protected Long CreateTime; + protected Long createTime; @XmlElement(name="MsgType") @XmlJavaTypeAdapter(AdapterCDATA.class) - protected String MsgType; + protected String msgType; public String getToUserName() { - return ToUserName; + return toUserName; } public void setToUserName(String toUserName) { - ToUserName = toUserName; + this.toUserName = toUserName; } public String getFromUserName() { - return FromUserName; + return fromUserName; } public void setFromUserName(String fromUserName) { - FromUserName = fromUserName; + this.fromUserName = fromUserName; } public Long getCreateTime() { - return CreateTime; + return createTime; } public void setCreateTime(Long createTime) { - CreateTime = createTime; + this.createTime = createTime; } public String getMsgType() { - return MsgType; + return msgType; } public void setMsgType(String msgType) { - MsgType = msgType; + this.msgType = msgType; } public String toXml() { @@ -81,9 +76,9 @@ public class WxXmlOutMessage { * 转换成加密的xml格式 * @return */ - public String toEncryptedXml(WxConfigStorage wxConfigStorage) { + public String toEncryptedXml(WxMpConfigStorage wxMpConfigStorage) { String plainXml = toXml(); - WxCryptUtil pc = new WxCryptUtil(wxConfigStorage); + WxMpCryptUtil pc = new WxMpCryptUtil(wxMpConfigStorage); return pc.encrypt(plainXml); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMewsMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMewsMessage.java new file mode 100644 index 00000000..527dc6a7 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMewsMessage.java @@ -0,0 +1,95 @@ +package me.chanjar.weixin.mp.bean; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.util.xml.AdapterCDATA; + +import javax.xml.bind.annotation.*; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import java.util.ArrayList; +import java.util.List; + +@XmlRootElement(name = "xml") +@XmlAccessorType(XmlAccessType.FIELD) +public class WxMpXmlOutMewsMessage extends WxMpXmlOutMessage { + + @XmlElement(name = "ArticleCount") + protected int articleCount; + + @XmlElementWrapper(name="Articles") + @XmlElement(name = "item") + protected final List articles = new ArrayList(); + + public WxMpXmlOutMewsMessage() { + this.msgType = WxConsts.XML_MSG_NEWS; + } + + public int getArticleCount() { + return articleCount; + } + + public void addArticle(Item item) { + this.articles.add(item); + this.articleCount = this.articles.size(); + } + + public List getArticles() { + return articles; + } + + + @XmlRootElement(name = "Item") + @XmlAccessorType(XmlAccessType.FIELD) + public static class Item { + + @XmlElement(name = "Title") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String Title; + + @XmlElement(name = "Description") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String Description; + + @XmlElement(name="PicUrl") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String PicUrl; + + @XmlElement(name="Url") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String Url; + + public String getTitle() { + return Title; + } + + public void setTitle(String title) { + Title = title; + } + + public String getDescription() { + return Description; + } + + public void setDescription(String description) { + Description = description; + } + + public String getPicUrl() { + return PicUrl; + } + + public void setPicUrl(String picUrl) { + PicUrl = picUrl; + } + + public String getUrl() { + return Url; + } + + public void setUrl(String url) { + Url = url; + } + + } + + +} diff --git a/src/main/java/me/chanjar/weixin/bean/WxXmlOutMusicMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMusicMessage.java similarity index 67% rename from src/main/java/me/chanjar/weixin/bean/WxXmlOutMusicMessage.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMusicMessage.java index 545b5274..782b5dbb 100644 --- a/src/main/java/me/chanjar/weixin/bean/WxXmlOutMusicMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMusicMessage.java @@ -1,4 +1,7 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.mp.bean; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.util.xml.AdapterCDATA; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @@ -6,18 +9,15 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.util.xml.AdapterCDATA; - @XmlRootElement(name = "xml") @XmlAccessorType(XmlAccessType.FIELD) -public class WxXmlOutMusicMessage extends WxXmlOutMessage { +public class WxMpXmlOutMusicMessage extends WxMpXmlOutMessage { @XmlElement(name = "Music") protected final Music music = new Music(); - public WxXmlOutMusicMessage() { - this.MsgType = WxConsts.XML_MSG_MUSIC; + public WxMpXmlOutMusicMessage() { + this.msgType = WxConsts.XML_MSG_MUSIC; } public String getTitle() { @@ -52,12 +52,12 @@ public class WxXmlOutMusicMessage extends WxXmlOutMessage { music.setMusicUrl(musicUrl); } - public String getHQMusicUrl() { - return music.getHQMusicUrl(); + public String getHqMusicUrl() { + return music.getHqMusicUrl(); } - public void setHQMusicUrl(String hQMusicUrl) { - music.setHQMusicUrl(hQMusicUrl); + public void setHqMusicUrl(String hqMusicUrl) { + music.setHqMusicUrl(hqMusicUrl); } @XmlRootElement(name = "Music") @@ -66,62 +66,62 @@ public class WxXmlOutMusicMessage extends WxXmlOutMessage { @XmlElement(name = "Title") @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Title; + private String title; @XmlElement(name = "Description") @XmlJavaTypeAdapter(AdapterCDATA.class) - private String Description; + private String description; @XmlElement(name="ThumbMediaId") @XmlJavaTypeAdapter(AdapterCDATA.class) - private String ThumbMediaId; + private String thumbMediaId; @XmlElement(name="MusicUrl") @XmlJavaTypeAdapter(AdapterCDATA.class) - private String MusicUrl; + private String musicUrl; @XmlElement(name="HQMusicUrl") @XmlJavaTypeAdapter(AdapterCDATA.class) - private String HQMusicUrl; + private String hqMusicUrl; public String getTitle() { - return Title; + return title; } public void setTitle(String title) { - Title = title; + this.title = title; } public String getDescription() { - return Description; + return description; } public void setDescription(String description) { - Description = description; + this.description = description; } public String getThumbMediaId() { - return ThumbMediaId; + return thumbMediaId; } public void setThumbMediaId(String thumbMediaId) { - ThumbMediaId = thumbMediaId; + this.thumbMediaId = thumbMediaId; } public String getMusicUrl() { - return MusicUrl; + return musicUrl; } public void setMusicUrl(String musicUrl) { - MusicUrl = musicUrl; + this.musicUrl = musicUrl; } - public String getHQMusicUrl() { - return HQMusicUrl; + public String getHqMusicUrl() { + return hqMusicUrl; } - public void setHQMusicUrl(String hQMusicUrl) { - HQMusicUrl = hQMusicUrl; + public void setHqMusicUrl(String hqMusicUrl) { + this.hqMusicUrl = hqMusicUrl; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutTextMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutTextMessage.java new file mode 100644 index 00000000..3542e07b --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutTextMessage.java @@ -0,0 +1,33 @@ +package me.chanjar.weixin.mp.bean; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.util.xml.AdapterCDATA; + +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; + +@XmlRootElement(name = "xml") +@XmlAccessorType(XmlAccessType.FIELD) +public class WxMpXmlOutTextMessage extends WxMpXmlOutMessage { + + @XmlElement(name="Content") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String content; + + public WxMpXmlOutTextMessage() { + this.msgType = WxConsts.XML_MSG_TEXT; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutVideoMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutVideoMessage.java new file mode 100644 index 00000000..4b192cf7 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutVideoMessage.java @@ -0,0 +1,90 @@ +package me.chanjar.weixin.mp.bean; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.util.xml.AdapterCDATA; + +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; + +@XmlRootElement(name = "xml") +@XmlAccessorType(XmlAccessType.FIELD) +public class WxMpXmlOutVideoMessage extends WxMpXmlOutMessage { + + @XmlElement(name = "Video") + protected final Video video = new Video(); + + public WxMpXmlOutVideoMessage() { + this.msgType = WxConsts.XML_MSG_VIDEO; + } + + public String getMediaId() { + return video.getMediaId(); + } + + public void setMediaId(String mediaId) { + video.setMediaId(mediaId); + } + + public String getTitle() { + return video.getTitle(); + } + + public void setTitle(String title) { + video.setTitle(title); + } + + public String getDescription() { + return video.getDescription(); + } + + public void setDescription(String description) { + video.setDescription(description); + } + + + @XmlRootElement(name = "Video") + @XmlAccessorType(XmlAccessType.FIELD) + private static class Video { + + @XmlElement(name = "MediaId") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String mediaId; + + @XmlElement(name = "Title") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String title; + + @XmlElement(name = "Description") + @XmlJavaTypeAdapter(AdapterCDATA.class) + private String description; + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutVoiceMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutVoiceMessage.java new file mode 100644 index 00000000..59f164ba --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutVoiceMessage.java @@ -0,0 +1,32 @@ +package me.chanjar.weixin.mp.bean; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.util.xml.MediaIdMarshaller; + +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; + +@XmlRootElement(name = "xml") +@XmlAccessorType(XmlAccessType.FIELD) +public class WxMpXmlOutVoiceMessage extends WxMpXmlOutMessage { + + @XmlElement(name="Voice") + @XmlJavaTypeAdapter(MediaIdMarshaller.class) + private String mediaId; + + public WxMpXmlOutVoiceMessage() { + this.msgType = WxConsts.XML_MSG_VOICE; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/BaseBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/BaseBuilder.java new file mode 100644 index 00000000..18bf81f9 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/BaseBuilder.java @@ -0,0 +1,20 @@ +package me.chanjar.weixin.mp.bean.custombuilder; + +import me.chanjar.weixin.mp.bean.WxMpCustomMessage; + +public class BaseBuilder { + protected String msgType; + protected String toUser; + + public T toUser(String toUser) { + this.toUser = toUser; + return (T) this; + } + + public WxMpCustomMessage build() { + WxMpCustomMessage m = new WxMpCustomMessage(); + m.setMsgType(this.msgType); + m.setToUser(this.toUser); + return m; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/ImageBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/ImageBuilder.java new file mode 100644 index 00000000..1c37b46e --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/ImageBuilder.java @@ -0,0 +1,31 @@ +package me.chanjar.weixin.mp.bean.custombuilder; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.WxMpCustomMessage; + +/** + * 获得消息builder + *
+ * 用法: WxMpCustomMessage m = WxMpCustomMessage.IMAGE().mediaId(...).toUser(...).build();
+ * 
+ * @author chanjarster + * + */ +public final class ImageBuilder extends BaseBuilder { + private String mediaId; + + public ImageBuilder() { + this.msgType = WxConsts.CUSTOM_MSG_IMAGE; + } + + public ImageBuilder mediaId(String media_id) { + this.mediaId = media_id; + return this; + } + + public WxMpCustomMessage build() { + WxMpCustomMessage m = super.build(); + m.setMediaId(this.mediaId); + return m; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/MusicBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/MusicBuilder.java new file mode 100644 index 00000000..5c1abe38 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/MusicBuilder.java @@ -0,0 +1,64 @@ +package me.chanjar.weixin.mp.bean.custombuilder; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.WxMpCustomMessage; + +/** + * 音乐消息builder + *
+ * 用法: WxMpCustomMessage m = WxMpCustomMessage.MUSIC()
+ *                      .musicUrl(...)
+ *                      .hqMusicUrl(...)
+ *                      .title(...)
+ *                      .thumbMediaId(..)
+ *                      .description(..)
+ *                      .toUser(...)
+ *                      .build();
+ * 
+ */ +public final class MusicBuilder extends BaseBuilder { + private String title; + private String description; + private String thumbMediaId; + private String musicUrl; + private String hqMusicUrl; + + public MusicBuilder() { + this.msgType = WxConsts.CUSTOM_MSG_MUSIC; + } + + public MusicBuilder musicUrl(String musicurl) { + this.musicUrl = musicurl; + return this; + } + + public MusicBuilder hqMusicUrl(String hqMusicurl) { + this.hqMusicUrl = hqMusicurl; + return this; + } + + public MusicBuilder title(String title) { + this.title = title; + return this; + } + + public MusicBuilder description(String description) { + this.description = description; + return this; + } + + public MusicBuilder thumbMediaId(String thumb_media_id) { + this.thumbMediaId = thumb_media_id; + return this; + } + + public WxMpCustomMessage build() { + WxMpCustomMessage m = super.build(); + m.setMusicUrl(this.musicUrl); + m.setHqMusicUrl(this.hqMusicUrl); + m.setTitle(title); + m.setDescription(description); + m.setThumbMediaId(thumbMediaId); + return m; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/NewsBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/NewsBuilder.java new file mode 100644 index 00000000..825e72f8 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/NewsBuilder.java @@ -0,0 +1,36 @@ +package me.chanjar.weixin.mp.bean.custombuilder; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.WxMpCustomMessage; + +import java.util.ArrayList; +import java.util.List; + +/** + * 图文消息builder + *
+ * 用法:
+ * WxMpCustomMessage m = WxMpCustomMessage.NEWS().addArticle(article).toUser(...).build();
+ * 
+ * @author chanjarster + * + */ +public final class NewsBuilder extends BaseBuilder { + + private List articles = new ArrayList(); + + public NewsBuilder() { + this.msgType = WxConsts.CUSTOM_MSG_NEWS; + } + + public NewsBuilder addArticle(WxMpCustomMessage.WxArticle article) { + this.articles.add(article); + return this; + } + + public WxMpCustomMessage build() { + WxMpCustomMessage m = super.build(); + m.setArticles(this.articles); + return m; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/TextBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/TextBuilder.java new file mode 100644 index 00000000..11249d6d --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/TextBuilder.java @@ -0,0 +1,31 @@ +package me.chanjar.weixin.mp.bean.custombuilder; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.WxMpCustomMessage; + +/** + * 文本消息builder + *
+ * 用法: WxMpCustomMessage m = WxMpCustomMessage.TEXT().content(...).toUser(...).build();
+ * 
+ * @author chanjarster + * + */ +public final class TextBuilder extends BaseBuilder { + private String content; + + public TextBuilder() { + this.msgType = WxConsts.CUSTOM_MSG_TEXT; + } + + public TextBuilder content(String content) { + this.content = content; + return this; + } + + public WxMpCustomMessage build() { + WxMpCustomMessage m = super.build(); + m.setContent(this.content); + return m; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/VideoBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/VideoBuilder.java new file mode 100644 index 00000000..a871d491 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/VideoBuilder.java @@ -0,0 +1,58 @@ +package me.chanjar.weixin.mp.bean.custombuilder; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.WxMpCustomMessage; + +/** + * 视频消息builder + *
+ * 用法: WxMpCustomMessage m = WxMpCustomMessage.VOICE()
+ *                              .mediaId(...)
+ *                              .title(...)
+ *                              .thumbMediaId(..)
+ *                              .description(..)
+ *                              .toUser(...)
+ *                              .build();
+ * 
+ * @author chanjarster + * + */ +public final class VideoBuilder extends BaseBuilder { + private String mediaId; + private String title; + private String description; + private String thumbMediaId; + + public VideoBuilder() { + this.msgType = WxConsts.CUSTOM_MSG_VIDEO; + } + + public VideoBuilder mediaId(String mediaId) { + this.mediaId = mediaId; + return this; + } + + public VideoBuilder title(String title) { + this.title = title; + return this; + } + + public VideoBuilder description(String description) { + this.description = description; + return this; + } + + public VideoBuilder thumbMediaId(String thumb_media_id) { + this.thumbMediaId = thumb_media_id; + return this; + } + + public WxMpCustomMessage build() { + WxMpCustomMessage m = super.build(); + m.setMediaId(this.mediaId); + m.setTitle(title); + m.setDescription(description); + m.setThumbMediaId(thumbMediaId); + return m; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/VoiceBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/VoiceBuilder.java new file mode 100644 index 00000000..3f81aeb0 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/custombuilder/VoiceBuilder.java @@ -0,0 +1,31 @@ +package me.chanjar.weixin.mp.bean.custombuilder; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.WxMpCustomMessage; + +/** + * 语音消息builder + *
+ * 用法: WxMpCustomMessage m = WxMpCustomMessage.VOICE().mediaId(...).toUser(...).build();
+ * 
+ * @author chanjarster + * + */ +public final class VoiceBuilder extends BaseBuilder { + private String mediaId; + + public VoiceBuilder() { + this.msgType = WxConsts.CUSTOM_MSG_VOICE; + } + + public VoiceBuilder mediaId(String media_id) { + this.mediaId = media_id; + return this; + } + + public WxMpCustomMessage build() { + WxMpCustomMessage m = super.build(); + m.setMediaId(this.mediaId); + return m; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/BaseBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/BaseBuilder.java new file mode 100644 index 00000000..77db2617 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/BaseBuilder.java @@ -0,0 +1,29 @@ +package me.chanjar.weixin.mp.bean.outxmlbuilder; + +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; + +public abstract class BaseBuilder { + + protected String toUserName; + + protected String fromUserName; + + public BuilderType toUser(String touser) { + this.toUserName = touser; + return (BuilderType) this; + } + + public BuilderType fromUser(String fromusername) { + this.fromUserName = fromusername; + return (BuilderType) this; + } + + public abstract ValueType build(); + + public void setCommon(WxMpXmlOutMessage m) { + m.setToUserName(this.toUserName); + m.setFromUserName(this.fromUserName); + m.setCreateTime(System.currentTimeMillis() / 1000l); + } + +} diff --git a/src/main/java/me/chanjar/weixin/bean/outxmlbuilder/ImageBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/ImageBuilder.java similarity index 56% rename from src/main/java/me/chanjar/weixin/bean/outxmlbuilder/ImageBuilder.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/ImageBuilder.java index 0cb18ccc..f127406a 100644 --- a/src/main/java/me/chanjar/weixin/bean/outxmlbuilder/ImageBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/ImageBuilder.java @@ -1,12 +1,12 @@ -package me.chanjar.weixin.bean.outxmlbuilder; +package me.chanjar.weixin.mp.bean.outxmlbuilder; -import me.chanjar.weixin.bean.WxXmlOutImageMessage; +import me.chanjar.weixin.mp.bean.WxMpMpXmlOutImageMessage; /** * 图片消息builder * @author chanjarster */ -public final class ImageBuilder extends BaseBuilder { +public final class ImageBuilder extends BaseBuilder { private String mediaId; @@ -15,8 +15,8 @@ public final class ImageBuilder extends BaseBuilder { +public final class MusicBuilder extends BaseBuilder { private String title; private String description; - private String hQMusicUrl; + private String hqMusicUrl; private String musicUrl; private String thumbMediaId; @@ -25,8 +25,8 @@ public final class MusicBuilder extends BaseBuilder { + + protected final List articles = new ArrayList(); + + public NewsBuilder addArticle(WxMpXmlOutMewsMessage.Item item) { + this.articles.add(item); + return this; + } + + public WxMpXmlOutMewsMessage build() { + WxMpXmlOutMewsMessage m = new WxMpXmlOutMewsMessage(); + for(WxMpXmlOutMewsMessage.Item item : articles) { + m.addArticle(item); + } + setCommon(m); + return m; + } + +} diff --git a/src/main/java/me/chanjar/weixin/bean/outxmlbuilder/TextBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/TextBuilder.java similarity index 57% rename from src/main/java/me/chanjar/weixin/bean/outxmlbuilder/TextBuilder.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/TextBuilder.java index 56393a33..8352ddea 100644 --- a/src/main/java/me/chanjar/weixin/bean/outxmlbuilder/TextBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/TextBuilder.java @@ -1,13 +1,13 @@ -package me.chanjar.weixin.bean.outxmlbuilder; +package me.chanjar.weixin.mp.bean.outxmlbuilder; -import me.chanjar.weixin.bean.WxXmlOutTextMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutTextMessage; /** * 文本消息builder * @author chanjarster * */ -public final class TextBuilder extends BaseBuilder { +public final class TextBuilder extends BaseBuilder { private String content; public TextBuilder content(String content) { @@ -15,8 +15,8 @@ public final class TextBuilder extends BaseBuilder { +public final class VideoBuilder extends BaseBuilder { private String mediaId; private String title; @@ -26,8 +26,8 @@ public final class VideoBuilder extends BaseBuilder { +public final class VoiceBuilder extends BaseBuilder { private String mediaId; @@ -15,8 +15,8 @@ public final class VoiceBuilder extends BaseBuilder + * 群发消息一发送就返回的结果 + * + * 真正的群发消息是否发送成功要看 + * http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口#.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81.E7.BE.A4.E5.8F.91.E7.BB.93.E6.9E.9C + * + *
+ * @author chanjarster + * + */ +public class WxMpMassSendResult { + + private String errorCode; + private String errorMsg; + private String msgId; + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMsg() { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) { + this.errorMsg = errorMsg; + } + + public String getMsgId() { + return msgId; + } + + public void setMsgId(String msgId) { + this.msgId = msgId; + } + + public static WxMpMassSendResult fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpMassSendResult.class); + } + + @Override + public String toString() { + return "WxMassSendResult [errcode=" + errorCode + ", errmsg=" + errorMsg + ", msg_id=" + msgId + "]"; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java new file mode 100644 index 00000000..e0ed145b --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java @@ -0,0 +1,52 @@ +package me.chanjar.weixin.mp.bean.result; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +/** + *
+ * 上传群发用的素材的结果
+ * 视频和图文消息需要在群发前上传素材
+ * 
+ * @author chanjarster + * + */ +public class WxMpMassUploadResult { + + private String type; + private String mediaId; + private long createdAt; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public long getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(long createdAt) { + this.createdAt = createdAt; + } + + public static WxMpMassUploadResult fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpMassUploadResult.class); + } + + @Override + public String toString() { + return "WxUploadResult [type=" + type + ", media_id=" + mediaId + ", created_at=" + createdAt + "]"; + } + +} diff --git a/src/main/java/me/chanjar/weixin/bean/result/WxQrCodeTicket.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java similarity index 69% rename from src/main/java/me/chanjar/weixin/bean/result/WxQrCodeTicket.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java index d9da02aa..bf240c57 100644 --- a/src/main/java/me/chanjar/weixin/bean/result/WxQrCodeTicket.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java @@ -1,13 +1,13 @@ -package me.chanjar.weixin.bean.result; +package me.chanjar.weixin.mp.bean.result; -import me.chanjar.weixin.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** * 换取二维码的Ticket * * @author chanjarster */ -public class WxQrCodeTicket { +public class WxMpQrCodeTicket { protected String ticket; protected int expire_seconds = -1; @@ -40,7 +40,7 @@ public class WxQrCodeTicket { this.url = url; } - public static WxQrCodeTicket fromJson(String json) { - return WxGsonBuilder.INSTANCE.create().fromJson(json, WxQrCodeTicket.class); + public static WxMpQrCodeTicket fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpQrCodeTicket.class); } } diff --git a/src/main/java/me/chanjar/weixin/bean/result/WxUser.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java similarity index 57% rename from src/main/java/me/chanjar/weixin/bean/result/WxUser.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java index 1893604a..fa4aee6d 100644 --- a/src/main/java/me/chanjar/weixin/bean/result/WxUser.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java @@ -1,25 +1,25 @@ -package me.chanjar.weixin.bean.result; +package me.chanjar.weixin.mp.bean.result; -import me.chanjar.weixin.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** * 微信用户信息 * @author chanjarster * */ -public class WxUser { +public class WxMpUser { protected boolean subscribe; - protected String openid; + protected String openId; protected String nickname; protected String sex; protected String language; protected String city; protected String province; protected String country; - protected String headimgurl; - protected long subscribe_time; - protected String unionid; + protected String headImgUrl; + protected long subscribeTime; + protected String unionId; public boolean isSubscribe() { return subscribe; @@ -27,11 +27,11 @@ public class WxUser { public void setSubscribe(boolean subscribe) { this.subscribe = subscribe; } - public String getOpenid() { - return openid; + public String getOpenId() { + return openId; } - public void setOpenid(String openid) { - this.openid = openid; + public void setOpenId(String openId) { + this.openId = openId; } public String getNickname() { return nickname; @@ -69,27 +69,27 @@ public class WxUser { public void setCountry(String country) { this.country = country; } - public String getHeadimgurl() { - return headimgurl; + public String getHeadImgUrl() { + return headImgUrl; } - public void setHeadimgurl(String headimgurl) { - this.headimgurl = headimgurl; + public void setHeadImgUrl(String headImgUrl) { + this.headImgUrl = headImgUrl; } - public long getSubscribe_time() { - return subscribe_time; + public long getSubscribeTime() { + return subscribeTime; } - public void setSubscribe_time(long subscribe_time) { - this.subscribe_time = subscribe_time; + public void setSubscribeTime(long subscribeTime) { + this.subscribeTime = subscribeTime; } - public String getUnionid() { - return unionid; + public String getUnionId() { + return unionId; } - public void setUnionid(String unionid) { - this.unionid = unionid; + public void setUnionId(String unionId) { + this.unionId = unionId; } - public static WxUser fromJson(String json) { - return WxGsonBuilder.INSTANCE.create().fromJson(json, WxUser.class); + public static WxMpUser fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUser.class); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserList.java new file mode 100644 index 00000000..489d5bed --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserList.java @@ -0,0 +1,47 @@ +package me.chanjar.weixin.mp.bean.result; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.util.ArrayList; +import java.util.List; + +/** + * 关注者列表 + * @author chanjarster + * + */ +public class WxMpUserList { + + protected int total = -1; + protected int count = -1; + protected List openIds = new ArrayList(); + protected String nextOpenId; + public int getTotal() { + return total; + } + public void setTotal(int total) { + this.total = total; + } + public int getCount() { + return count; + } + public void setCount(int count) { + this.count = count; + } + public List getOpenIds() { + return openIds; + } + public void setOpenIds(List openIds) { + this.openIds = openIds; + } + public String getNextOpenId() { + return nextOpenId; + } + public void setNextOpenId(String nextOpenId) { + this.nextOpenId = nextOpenId; + } + + public static WxMpUserList fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUserList.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java new file mode 100755 index 00000000..39165b5c --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java @@ -0,0 +1,41 @@ +/** + * 对公众平台发送给公众账号的消息加解密示例代码. + * + * @copyright Copyright (c) 1998-2014 Tencent Inc. + */ + +// ------------------------------------------------------------------------ + +/** + * 针对org.apache.commons.codec.binary.Base64, + * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) + * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi + */ +package me.chanjar.weixin.mp.util.crypto; + +import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import org.apache.commons.codec.binary.Base64; + +public class WxMpCryptUtil extends me.chanjar.weixin.common.util.crypto.WxCryptUtil { + + /** + * 构造函数 + * + * @param wxMpConfigStorage + */ + public WxMpCryptUtil(WxMpConfigStorage wxMpConfigStorage) { + /* + * @param token 公众平台上,开发者设置的token + * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey + * @param appId 公众平台appid + */ + String encodingAesKey = wxMpConfigStorage.getAesKey(); + String token = wxMpConfigStorage.getToken(); + String appId = wxMpConfigStorage.getAppId(); + + this.token = token; + this.appidOrCorpid = appId; + this.aesKey = Base64.decodeBase64(encodingAesKey + "="); + } + +} diff --git a/src/main/java/me/chanjar/weixin/util/http/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java similarity index 72% rename from src/main/java/me/chanjar/weixin/util/http/QrCodeRequestExecutor.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java index b33fb501..554c9b8f 100644 --- a/src/main/java/me/chanjar/weixin/util/http/QrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java @@ -1,31 +1,33 @@ -package me.chanjar.weixin.util.http; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URLEncoder; -import java.util.UUID; +package me.chanjar.weixin.mp.util.http; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import me.chanjar.weixin.common.exception.WxErrorException; import org.apache.http.Header; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.entity.ContentType; -import me.chanjar.weixin.bean.result.WxError; -import me.chanjar.weixin.bean.result.WxQrCodeTicket; -import me.chanjar.weixin.exception.WxErrorException; -import me.chanjar.weixin.util.fs.FileUtils; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.UUID; /** * 获得QrCode图片 请求执行器 * @author chanjarster * */ -public class QrCodeRequestExecutor implements RequestExecutor { +public class QrCodeRequestExecutor implements RequestExecutor { @Override - public File execute(String uri, WxQrCodeTicket ticket) throws WxErrorException, ClientProtocolException, IOException { + public File execute(String uri, WxMpQrCodeTicket ticket) throws WxErrorException, ClientProtocolException, IOException { if (ticket != null) { if (uri.indexOf('?') == -1) { uri += '?'; diff --git a/src/main/java/me/chanjar/weixin/util/json/WxCustomMessageGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCustomMessageGsonAdapter.java similarity index 52% rename from src/main/java/me/chanjar/weixin/util/json/WxCustomMessageGsonAdapter.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCustomMessageGsonAdapter.java index 70821659..6ff4b773 100644 --- a/src/main/java/me/chanjar/weixin/util/json/WxCustomMessageGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCustomMessageGsonAdapter.java @@ -6,76 +6,71 @@ * arose from modification of the original source, or other redistribution of this source * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. */ -package me.chanjar.weixin.util.json; +package me.chanjar.weixin.mp.util.json; -import java.lang.reflect.Type; - -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.bean.WxCustomMessage; +import com.google.gson.*; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.WxMpCustomMessage; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; +import java.lang.reflect.Type; /** * * @author qianjia * */ -public class WxCustomMessageGsonAdapter implements JsonSerializer { +public class WxMpCustomMessageGsonAdapter implements JsonSerializer { - public JsonElement serialize(WxCustomMessage message, Type typeOfSrc, JsonSerializationContext context) { + public JsonElement serialize(WxMpCustomMessage message, Type typeOfSrc, JsonSerializationContext context) { JsonObject messageJson = new JsonObject(); - messageJson.addProperty("touser", message.getTouser()); - messageJson.addProperty("msgtype", message.getMsgtype()); + messageJson.addProperty("touser", message.getToUser()); + messageJson.addProperty("msgtype", message.getMsgType()); - if (WxConsts.CUSTOM_MSG_TEXT.equals(message.getMsgtype())) { + if (WxConsts.CUSTOM_MSG_TEXT.equals(message.getMsgType())) { JsonObject text = new JsonObject(); text.addProperty("content", message.getContent()); messageJson.add("text", text); } - if (WxConsts.CUSTOM_MSG_IMAGE.equals(message.getMsgtype())) { + if (WxConsts.CUSTOM_MSG_IMAGE.equals(message.getMsgType())) { JsonObject image = new JsonObject(); - image.addProperty("media_id", message.getMedia_id()); + image.addProperty("media_id", message.getMediaId()); messageJson.add("image", image); } - if (WxConsts.CUSTOM_MSG_VOICE.equals(message.getMsgtype())) { + if (WxConsts.CUSTOM_MSG_VOICE.equals(message.getMsgType())) { JsonObject voice = new JsonObject(); - voice.addProperty("media_id", message.getMedia_id()); + voice.addProperty("media_id", message.getMediaId()); messageJson.add("voice", voice); } - if (WxConsts.CUSTOM_MSG_VIDEO.equals(message.getMsgtype())) { + if (WxConsts.CUSTOM_MSG_VIDEO.equals(message.getMsgType())) { JsonObject video = new JsonObject(); - video.addProperty("media_id", message.getMedia_id()); - video.addProperty("thumb_media_id", message.getThumb_media_id()); + video.addProperty("media_id", message.getMediaId()); + video.addProperty("thumb_media_id", message.getThumbMediaId()); video.addProperty("title", message.getTitle()); video.addProperty("description", message.getDescription()); messageJson.add("video", video); } - if (WxConsts.CUSTOM_MSG_MUSIC.equals(message.getMsgtype())) { + if (WxConsts.CUSTOM_MSG_MUSIC.equals(message.getMsgType())) { JsonObject music = new JsonObject(); music.addProperty("title", message.getTitle()); music.addProperty("description", message.getDescription()); - music.addProperty("thumb_media_id", message.getThumb_media_id()); - music.addProperty("musicurl", message.getMusicurl()); - music.addProperty("hqmusicurl", message.getHqmusicurl()); + music.addProperty("thumb_media_id", message.getThumbMediaId()); + music.addProperty("musicurl", message.getMusicUrl()); + music.addProperty("hqmusicurl", message.getHqMusicUrl()); messageJson.add("music", music); } - if (WxConsts.CUSTOM_MSG_NEWS.equals(message.getMsgtype())) { + if (WxConsts.CUSTOM_MSG_NEWS.equals(message.getMsgType())) { JsonArray articleJsonArray = new JsonArray(); - for (WxCustomMessage.WxArticle article : message.getArticles()) { + for (WxMpCustomMessage.WxArticle article : message.getArticles()) { JsonObject articleJson = new JsonObject(); articleJson.addProperty("title", article.getTitle()); articleJson.addProperty("description", article.getDescription()); articleJson.addProperty("url", article.getUrl()); - articleJson.addProperty("picurl", article.getPicurl()); + articleJson.addProperty("picurl", article.getPicUrl()); articleJsonArray.add(articleJson); } messageJson.add("articles", articleJsonArray); diff --git a/src/main/java/me/chanjar/weixin/util/json/WxGroupGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGroupGsonAdapter.java similarity index 67% rename from src/main/java/me/chanjar/weixin/util/json/WxGroupGsonAdapter.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGroupGsonAdapter.java index c95e84e9..63f0624e 100644 --- a/src/main/java/me/chanjar/weixin/util/json/WxGroupGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGroupGsonAdapter.java @@ -6,28 +6,22 @@ * arose from modification of the original source, or other redistribution of this source * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. */ -package me.chanjar.weixin.util.json; +package me.chanjar.weixin.mp.util.json; -import java.lang.reflect.Type; - -import me.chanjar.weixin.bean.WxGroup; +import com.google.gson.*; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.mp.bean.WxMpGroup; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; +import java.lang.reflect.Type; /** * * @author qianjia * */ -public class WxGroupGsonAdapter implements JsonSerializer, JsonDeserializer { +public class WxMpGroupGsonAdapter implements JsonSerializer, JsonDeserializer { - public JsonElement serialize(WxGroup group, Type typeOfSrc, JsonSerializationContext context) { + public JsonElement serialize(WxMpGroup group, Type typeOfSrc, JsonSerializationContext context) { JsonObject json = new JsonObject(); JsonObject groupJson = new JsonObject(); groupJson.addProperty("name", group.getName()); @@ -37,8 +31,8 @@ public class WxGroupGsonAdapter implements JsonSerializer, JsonDeserial return json; } - public WxGroup deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - WxGroup group = new WxGroup(); + public WxMpGroup deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + WxMpGroup group = new WxMpGroup(); JsonObject groupJson = json.getAsJsonObject(); if (json.getAsJsonObject().get("group") != null) { groupJson = json.getAsJsonObject().get("group").getAsJsonObject(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java new file mode 100644 index 00000000..021b660d --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java @@ -0,0 +1,31 @@ +package me.chanjar.weixin.mp.util.json; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import me.chanjar.weixin.mp.bean.*; +import me.chanjar.weixin.mp.bean.result.*; + +public class WxMpGsonBuilder { + + public static final GsonBuilder INSTANCE = new GsonBuilder(); + + static { + INSTANCE.disableHtmlEscaping(); + INSTANCE.registerTypeAdapter(WxMpCustomMessage.class, new WxMpCustomMessageGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMpMassNews.class, new WxMpMassNewsGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMpMassGroupMessage.class, new WxMpMassMessageGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMpMassOpenIdsMessage.class, new WxMpMassOpenIdsMessageGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMpGroup.class, new WxMpGroupGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMpUser.class, new WxUserGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMpUserList.class, new WxUserListGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMpMassVideo.class, new WxMpMassVideoAdapter()); + INSTANCE.registerTypeAdapter(WxMpMassSendResult.class, new WxMpMassSendResultAdapter()); + INSTANCE.registerTypeAdapter(WxMpMassUploadResult.class, new WxMpMassUploadResultAdapter()); + INSTANCE.registerTypeAdapter(WxMpQrCodeTicket.class, new WxQrCodeTicketAdapter()); + } + + public static Gson create() { + return INSTANCE.create(); + } + +} diff --git a/src/main/java/me/chanjar/weixin/util/json/WxMassMessageGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassMessageGsonAdapter.java similarity index 73% rename from src/main/java/me/chanjar/weixin/util/json/WxMassMessageGsonAdapter.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassMessageGsonAdapter.java index fb78ab4f..5b9a9845 100644 --- a/src/main/java/me/chanjar/weixin/util/json/WxMassMessageGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassMessageGsonAdapter.java @@ -6,35 +6,34 @@ * arose from modification of the original source, or other redistribution of this source * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. */ -package me.chanjar.weixin.util.json; - -import java.lang.reflect.Type; - -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.bean.WxMassGroupMessage; +package me.chanjar.weixin.mp.util.json; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.WxMpMassGroupMessage; + +import java.lang.reflect.Type; /** * * @author qianjia * */ -public class WxMassMessageGsonAdapter implements JsonSerializer { +public class WxMpMassMessageGsonAdapter implements JsonSerializer { - public JsonElement serialize(WxMassGroupMessage message, Type typeOfSrc, JsonSerializationContext context) { + public JsonElement serialize(WxMpMassGroupMessage message, Type typeOfSrc, JsonSerializationContext context) { JsonObject messageJson = new JsonObject(); JsonObject filter = new JsonObject(); - filter.addProperty("group_id", message.getGroup_id()); + filter.addProperty("group_id", message.getGroupId()); messageJson.add("filter", filter); if (WxConsts.MASS_MSG_NEWS.equals(message.getMsgtype())) { JsonObject sub = new JsonObject(); - sub.addProperty("media_id", message.getMedia_id()); + sub.addProperty("media_id", message.getMediaId()); messageJson.add(WxConsts.MASS_MSG_NEWS, sub); } if (WxConsts.MASS_MSG_TEXT.equals(message.getMsgtype())) { @@ -44,17 +43,17 @@ public class WxMassMessageGsonAdapter implements JsonSerializer { +public class WxMpMassNewsGsonAdapter implements JsonSerializer { - public JsonElement serialize(WxMassNews message, Type typeOfSrc, JsonSerializationContext context) { + public JsonElement serialize(WxMpMassNews message, Type typeOfSrc, JsonSerializationContext context) { JsonObject newsJson = new JsonObject(); JsonArray articleJsonArray = new JsonArray(); - for (WxMassNews.WxMassNewsArticle article : message.getArticles()) { + for (WxMpMassNews.WxMpMassNewsArticle article : message.getArticles()) { JsonObject articleJson = new JsonObject(); - articleJson.addProperty("thumb_media_id", article.getThumb_media_id()); + articleJson.addProperty("thumb_media_id", article.getThumbMediaId()); articleJson.addProperty("title", article.getTitle()); articleJson.addProperty("content", article.getContent()); if (null != article.getAuthor()) { articleJson.addProperty("author", article.getAuthor()); } - if (null != article.getContent_source_url()) { - articleJson.addProperty("content_source_url", article.getContent_source_url()); + if (null != article.getContentSourceUrl()) { + articleJson.addProperty("content_source_url", article.getContentSourceUrl()); } if (null != article.getDigest()) { articleJson.addProperty("digest", article.getDigest()); } - articleJson.addProperty("show_cover_pic", article.isShow_cover_pic() ? "1" : "0"); + articleJson.addProperty("show_cover_pic", article.isShowCoverPic() ? "1" : "0"); articleJsonArray.add(articleJson); } newsJson.add("articles", articleJsonArray); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassOpenIdsMessageGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassOpenIdsMessageGsonAdapter.java new file mode 100644 index 00000000..cd03addf --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassOpenIdsMessageGsonAdapter.java @@ -0,0 +1,62 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.mp.util.json; + +import com.google.gson.*; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage; + +import java.lang.reflect.Type; + +/** + * + * @author qianjia + * + */ +public class WxMpMassOpenIdsMessageGsonAdapter implements JsonSerializer { + + public JsonElement serialize(WxMpMassOpenIdsMessage message, Type typeOfSrc, JsonSerializationContext context) { + JsonObject messageJson = new JsonObject(); + + JsonArray toUsers = new JsonArray(); + for (String openId : message.getToUsers()) { + toUsers.add(new JsonPrimitive(openId)); + } + messageJson.add("touser", toUsers); + + if (WxConsts.MASS_MSG_NEWS.equals(message.getMsgType())) { + JsonObject sub = new JsonObject(); + sub.addProperty("media_id", message.getMediaId()); + messageJson.add(WxConsts.MASS_MSG_NEWS, sub); + } + if (WxConsts.MASS_MSG_TEXT.equals(message.getMsgType())) { + JsonObject sub = new JsonObject(); + sub.addProperty("content", message.getContent()); + messageJson.add(WxConsts.MASS_MSG_TEXT, sub); + } + if (WxConsts.MASS_MSG_VOICE.equals(message.getMsgType())) { + JsonObject sub = new JsonObject(); + sub.addProperty("media_id", message.getMediaId()); + messageJson.add(WxConsts.MASS_MSG_VOICE, sub); + } + if (WxConsts.MASS_MSG_IMAGE.equals(message.getMsgType())) { + JsonObject sub = new JsonObject(); + sub.addProperty("media_id", message.getMediaId()); + messageJson.add(WxConsts.MASS_MSG_IMAGE, sub); + } + if (WxConsts.MASS_MSG_VIDEO.equals(message.getMsgType())) { + JsonObject sub = new JsonObject(); + sub.addProperty("media_id", message.getMediaId()); + messageJson.add(WxConsts.MASS_MSG_VIDEO, sub); + } + messageJson.addProperty("msgtype", message.getMsgType()); + return messageJson; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassSendResultAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassSendResultAdapter.java new file mode 100644 index 00000000..99fc02b8 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassSendResultAdapter.java @@ -0,0 +1,40 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.mp.util.json; + +import com.google.gson.*; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult; + +import java.lang.reflect.Type; + +/** + * + * @author Daniel Qian + * + */ +public class WxMpMassSendResultAdapter implements JsonDeserializer { + + public WxMpMassSendResult deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + WxMpMassSendResult sendResult = new WxMpMassSendResult(); + JsonObject sendResultJsonObject = json.getAsJsonObject(); + + if (sendResultJsonObject.get("errcode") != null && !sendResultJsonObject.get("errcode").isJsonNull()) { + sendResult.setErrorCode(GsonHelper.getAsString(sendResultJsonObject.get("errcode"))); + } + if (sendResultJsonObject.get("errmsg") != null && !sendResultJsonObject.get("errmsg").isJsonNull()) { + sendResult.setErrorMsg(GsonHelper.getAsString(sendResultJsonObject.get("errmsg"))); + } + if (sendResultJsonObject.get("msg_id") != null && !sendResultJsonObject.get("msg_id").isJsonNull()) { + sendResult.setMsgId(GsonHelper.getAsString(sendResultJsonObject.get("msg_id"))); + } + return sendResult; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassUploadResultAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassUploadResultAdapter.java new file mode 100644 index 00000000..73f03382 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassUploadResultAdapter.java @@ -0,0 +1,40 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.mp.util.json; + +import com.google.gson.*; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult; + +import java.lang.reflect.Type; + +/** + * + * @author Daniel Qian + * + */ +public class WxMpMassUploadResultAdapter implements JsonDeserializer { + + public WxMpMassUploadResult deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + WxMpMassUploadResult uploadResult = new WxMpMassUploadResult(); + JsonObject uploadResultJsonObject = json.getAsJsonObject(); + + if (uploadResultJsonObject.get("type") != null && !uploadResultJsonObject.get("type").isJsonNull()) { + uploadResult.setType(GsonHelper.getAsString(uploadResultJsonObject.get("type"))); + } + if (uploadResultJsonObject.get("media_id") != null && !uploadResultJsonObject.get("media_id").isJsonNull()) { + uploadResult.setMediaId(GsonHelper.getAsString(uploadResultJsonObject.get("media_id"))); + } + if (uploadResultJsonObject.get("created_at") != null && !uploadResultJsonObject.get("created_at").isJsonNull()) { + uploadResult.setCreatedAt(GsonHelper.getAsPrimitiveLong(uploadResultJsonObject.get("created_at"))); + } + return uploadResult; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassVideoAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassVideoAdapter.java new file mode 100644 index 00000000..d4b37b81 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassVideoAdapter.java @@ -0,0 +1,34 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.mp.util.json; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import me.chanjar.weixin.mp.bean.WxMpMassVideo; + +import java.lang.reflect.Type; + +/** + * + * @author Daniel Qian + * + */ +public class WxMpMassVideoAdapter implements JsonSerializer { + + public JsonElement serialize(WxMpMassVideo message, Type typeOfSrc, JsonSerializationContext context) { + JsonObject messageJson = new JsonObject(); + messageJson.addProperty("media_id", message.getMediaId()); + messageJson.addProperty("description", message.getDescription()); + messageJson.addProperty("title", message.getTitle()); + return messageJson; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxQrCodeTicketAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxQrCodeTicketAdapter.java new file mode 100644 index 00000000..522d70d0 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxQrCodeTicketAdapter.java @@ -0,0 +1,40 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.mp.util.json; + +import com.google.gson.*; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; + +import java.lang.reflect.Type; + +/** + * + * @author Daniel Qian + * + */ +public class WxQrCodeTicketAdapter implements JsonDeserializer { + + public WxMpQrCodeTicket deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + WxMpQrCodeTicket ticket = new WxMpQrCodeTicket(); + JsonObject ticketJsonObject = json.getAsJsonObject(); + + if (ticketJsonObject.get("ticket") != null && !ticketJsonObject.get("ticket").isJsonNull()) { + ticket.setTicket(GsonHelper.getAsString(ticketJsonObject.get("ticket"))); + } + if (ticketJsonObject.get("expire_seconds") != null && !ticketJsonObject.get("expire_seconds").isJsonNull()) { + ticket.setExpire_seconds(GsonHelper.getAsPrimitiveInt(ticketJsonObject.get("expire_seconds"))); + } + if (ticketJsonObject.get("url") != null && !ticketJsonObject.get("url").isJsonNull()) { + ticket.setUrl(GsonHelper.getAsString(ticketJsonObject.get("url"))); + } + return ticket; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserGsonAdapter.java new file mode 100644 index 00000000..cbbc3080 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserGsonAdapter.java @@ -0,0 +1,48 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.mp.util.json; + +import com.google.gson.*; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.mp.bean.result.WxMpUser; + +import java.lang.reflect.Type; + +/** + * + * @author qianjia + * + */ +public class WxUserGsonAdapter implements JsonDeserializer { + + public WxMpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject o = json.getAsJsonObject(); + WxMpUser wxMpUser = new WxMpUser(); + wxMpUser.setSubscribe(new Integer(0).equals(GsonHelper.getInteger(o, "subscribe")) ? false : true); + wxMpUser.setCity(GsonHelper.getString(o, "city")); + wxMpUser.setCountry(GsonHelper.getString(o, "country")); + wxMpUser.setHeadImgUrl(GsonHelper.getString(o, "headimgurl")); + wxMpUser.setLanguage(GsonHelper.getString(o, "language")); + wxMpUser.setNickname(GsonHelper.getString(o, "nickname")); + wxMpUser.setOpenId(GsonHelper.getString(o, "openid")); + wxMpUser.setProvince(GsonHelper.getString(o, "province")); + wxMpUser.setSubscribeTime(GsonHelper.getLong(o, "subscribe_time")); + wxMpUser.setUnionId(GsonHelper.getString(o, "unionid")); + Integer sex = GsonHelper.getInteger(o, "sex"); + if(new Integer(1).equals(sex)) { + wxMpUser.setSex("男"); + } else if (new Integer(2).equals(sex)) { + wxMpUser.setSex("女"); + } else { + wxMpUser.setSex("未知"); + } + return wxMpUser; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserListGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserListGsonAdapter.java new file mode 100644 index 00000000..ec65735e --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserListGsonAdapter.java @@ -0,0 +1,37 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.mp.util.json; + +import com.google.gson.*; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.mp.bean.result.WxMpUserList; + +import java.lang.reflect.Type; + +/** + * + * @author qianjia + * + */ +public class WxUserListGsonAdapter implements JsonDeserializer { + + public WxMpUserList deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject o = json.getAsJsonObject(); + WxMpUserList wxMpUserList = new WxMpUserList(); + wxMpUserList.setTotal(GsonHelper.getInteger(o, "total")); + wxMpUserList.setCount(GsonHelper.getInteger(o, "count")); + wxMpUserList.setNextOpenId(GsonHelper.getString(o, "next_openid")); + JsonArray data = o.get("data").getAsJsonObject().get("openid").getAsJsonArray(); + for (int i = 0; i < data.size(); i++) { + wxMpUserList.getOpenIds().add(GsonHelper.getAsString(data.get(i))); + } + return wxMpUserList; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XmlTransformer.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XmlTransformer.java new file mode 100644 index 00000000..5e619746 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XmlTransformer.java @@ -0,0 +1,90 @@ +package me.chanjar.weixin.mp.util.xml; + +import com.sun.xml.bind.marshaller.CharacterEscapeHandler; +import me.chanjar.weixin.mp.bean.*; +import org.xml.sax.InputSource; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import java.io.*; + +public class XmlTransformer { + + protected static final JAXBContext JAXB_CONTEXT = initJAXBContext(); + + /** + * xml -> pojo + * + * @param clazz + * @param xml + * @return + * @throws JAXBException + */ + @SuppressWarnings("unchecked") + public static T fromXml(Class clazz, String xml) throws JAXBException { + Unmarshaller um = JAXB_CONTEXT.createUnmarshaller(); + T object = (T) um.unmarshal(new StringReader(xml)); + return object; + } + + @SuppressWarnings("unchecked") + public static T fromXml(Class clazz, InputStream is) throws JAXBException { + Unmarshaller um = JAXB_CONTEXT.createUnmarshaller(); + InputSource inputSource = new InputSource(is); + inputSource.setEncoding("utf-8"); + T object = (T) um.unmarshal(inputSource); + return object; + } + + /** + * pojo -> xml + * + * @param clazz + * @param object + * @return + * @throws JAXBException + */ + public static String toXml(Class clazz, T object) throws JAXBException { + StringWriter stringWriter = new StringWriter(); + toXml(clazz, object, stringWriter); + return stringWriter.getBuffer().toString(); + } + + public static void toXml(Class clazz, T object, Writer writer) throws JAXBException { + Marshaller m = JAXB_CONTEXT.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + m.setProperty(CharacterEscapeHandler.class.getName(), CHAR_ESCAPE_HANDLER); + m.marshal(object, writer); + } + + protected static final CharacterEscapeHandler CHAR_ESCAPE_HANDLER = new CharacterUnescapeHandler(); + + protected static class CharacterUnescapeHandler implements CharacterEscapeHandler { + public void escape(char[] ac, int i, int j, boolean flag, Writer writer) throws IOException { + writer.write(ac, i, j); + } + } + + private static JAXBContext initJAXBContext() { + /* + * JAXBContext对象是线程安全的,根据官方文档的建议将对象作为全局实例 + * https://jaxb.java.net/guide/Performance_and_thread_safety.html + */ + try { + return JAXBContext.newInstance( + WxMpXmlOutMessage.class, + WxMpMpXmlOutImageMessage.class, + WxMpXmlOutMewsMessage.class, + WxMpXmlOutMusicMessage.class, + WxMpXmlOutTextMessage.class, + WxMpXmlOutVideoMessage.class, + WxMpXmlOutVoiceMessage.class, + WxMpXmlMessage.class); + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/test/java/me/chanjar/weixin/api/ApiTestModule.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/ApiTestModule.java similarity index 73% rename from src/test/java/me/chanjar/weixin/api/ApiTestModule.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/ApiTestModule.java index 68a9f8a2..ca4cbc13 100644 --- a/src/test/java/me/chanjar/weixin/api/ApiTestModule.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/ApiTestModule.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.mp.api; import java.io.InputStream; @@ -9,10 +9,6 @@ import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; -import me.chanjar.weixin.api.WxInMemoryConfigStorage; -import me.chanjar.weixin.api.WxServiceImpl; -import me.chanjar.weixin.util.xml.XmlTransformer; - import com.google.inject.Binder; import com.google.inject.Module; import org.xml.sax.InputSource; @@ -23,12 +19,12 @@ public class ApiTestModule implements Module { public void configure(Binder binder) { try { InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml"); - WxXmlConfigStorage config = fromXml(WxXmlConfigStorage.class, is1); - WxServiceImpl wxService = new WxServiceImpl(); - wxService.setWxConfigStorage(config); + WxXmlMpInMemoryConfigStorage config = fromXml(WxXmlMpInMemoryConfigStorage.class, is1); + WxMpServiceImpl wxService = new WxMpServiceImpl(); + wxService.setWxMpConfigStorage(config); - binder.bind(WxServiceImpl.class).toInstance(wxService); - binder.bind(WxConfigStorage.class).toInstance(config); + binder.bind(WxMpServiceImpl.class).toInstance(wxService); + binder.bind(WxMpConfigStorage.class).toInstance(config); } catch (JAXBException e) { throw new RuntimeException(e); } @@ -44,7 +40,7 @@ public class ApiTestModule implements Module { @XmlRootElement(name = "xml") @XmlAccessorType(XmlAccessType.FIELD) - public static class WxXmlConfigStorage extends WxInMemoryConfigStorage { + public static class WxXmlMpInMemoryConfigStorage extends WxMpInMemoryConfigStorage { protected String openId; diff --git a/src/test/java/me/chanjar/weixin/api/WxBaseAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxBaseAPITest.java similarity index 76% rename from src/test/java/me/chanjar/weixin/api/WxBaseAPITest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxBaseAPITest.java index af524615..65d88928 100644 --- a/src/test/java/me/chanjar/weixin/api/WxBaseAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxBaseAPITest.java @@ -1,11 +1,11 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.mp.api; import org.apache.commons.lang3.StringUtils; import org.testng.Assert; import org.testng.annotations.Guice; import org.testng.annotations.Test; -import me.chanjar.weixin.exception.WxErrorException; +import me.chanjar.weixin.common.exception.WxErrorException; import com.google.inject.Inject; @@ -19,10 +19,10 @@ import com.google.inject.Inject; public class WxBaseAPITest { @Inject - protected WxServiceImpl wxService; + protected WxMpServiceImpl wxService; public void testRefreshAccessToken() throws WxErrorException { - WxConfigStorage configStorage = wxService.wxConfigStorage; + WxMpConfigStorage configStorage = wxService.wxMpConfigStorage; String before = configStorage.getAccessToken(); wxService.accessTokenRefresh(); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpCustomMessageAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpCustomMessageAPITest.java new file mode 100644 index 00000000..04e8400e --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpCustomMessageAPITest.java @@ -0,0 +1,34 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.WxMpCustomMessage; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import me.chanjar.weixin.common.exception.WxErrorException; + +import com.google.inject.Inject; + +/*** + * 测试发送客服消息 + * @author chanjarster + * + */ +@Test(groups="customMessageAPI", dependsOnGroups = "baseAPI") +@Guice(modules = ApiTestModule.class) +public class WxMpCustomMessageAPITest { + + @Inject + protected WxMpServiceImpl wxService; + + public void testSendCustomMessage() throws WxErrorException { + ApiTestModule.WxXmlMpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.wxMpConfigStorage; + WxMpCustomMessage message = new WxMpCustomMessage(); + message.setMsgType(WxConsts.CUSTOM_MSG_TEXT); + message.setToUser(configStorage.getOpenId()); + message.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); + + wxService.customMessageSend(message); + } + +} diff --git a/src/test/java/me/chanjar/weixin/api/WxGroupAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpGroupAPITest.java similarity index 69% rename from src/test/java/me/chanjar/weixin/api/WxGroupAPITest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpGroupAPITest.java index 74abb563..ca6f20ed 100644 --- a/src/test/java/me/chanjar/weixin/api/WxGroupAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpGroupAPITest.java @@ -1,13 +1,13 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.mp.api; import java.util.List; +import me.chanjar.weixin.mp.bean.WxMpGroup; import org.testng.Assert; import org.testng.annotations.Guice; import org.testng.annotations.Test; -import me.chanjar.weixin.bean.WxGroup; -import me.chanjar.weixin.exception.WxErrorException; +import me.chanjar.weixin.common.exception.WxErrorException; import com.google.inject.Inject; @@ -18,24 +18,24 @@ import com.google.inject.Inject; */ @Test(groups = "groupAPI", dependsOnGroups = "baseAPI") @Guice(modules = ApiTestModule.class) -public class WxGroupAPITest { +public class WxMpGroupAPITest { @Inject - protected WxServiceImpl wxService; + protected WxMpServiceImpl wxService; - protected WxGroup group; + protected WxMpGroup group; public void testGroupCreate() throws WxErrorException { - WxGroup res = wxService.groupCreate("测试分组1"); + WxMpGroup res = wxService.groupCreate("测试分组1"); Assert.assertEquals(res.getName(), "测试分组1"); } @Test(dependsOnMethods="testGroupCreate") public void testGroupGet() throws WxErrorException { - List groupList = wxService.groupGet(); + List groupList = wxService.groupGet(); Assert.assertNotNull(groupList); Assert.assertTrue(groupList.size() > 0); - for (WxGroup g : groupList) { + for (WxMpGroup g : groupList) { group = g; Assert.assertNotNull(g.getName()); } diff --git a/src/test/java/me/chanjar/weixin/api/WxMassMessageAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMassMessageAPITest.java similarity index 55% rename from src/test/java/me/chanjar/weixin/api/WxMassMessageAPITest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMassMessageAPITest.java index c942ce38..78a48c2f 100644 --- a/src/test/java/me/chanjar/weixin/api/WxMassMessageAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMassMessageAPITest.java @@ -1,23 +1,22 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.mp.api; import java.io.IOException; import java.io.InputStream; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.mp.bean.WxMpMassGroupMessage; +import me.chanjar.weixin.mp.bean.WxMpMassNews; +import me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage; +import me.chanjar.weixin.mp.bean.WxMpMassVideo; +import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult; +import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Guice; import org.testng.annotations.Test; -import me.chanjar.weixin.api.ApiTestModule.WxXmlConfigStorage; -import me.chanjar.weixin.bean.WxMassGroupMessage; -import me.chanjar.weixin.bean.WxMassNews; -import me.chanjar.weixin.bean.WxMassNews.WxMassNewsArticle; -import me.chanjar.weixin.bean.WxMassOpenIdsMessage; -import me.chanjar.weixin.bean.WxMassVideo; -import me.chanjar.weixin.bean.result.WxMassSendResult; -import me.chanjar.weixin.bean.result.WxMassUploadResult; -import me.chanjar.weixin.bean.result.WxMediaUploadResult; -import me.chanjar.weixin.exception.WxErrorException; +import me.chanjar.weixin.common.exception.WxErrorException; import com.google.inject.Inject; @@ -28,61 +27,61 @@ import com.google.inject.Inject; */ @Test(groups = "massAPI", dependsOnGroups = { "baseAPI", "mediaAPI", "groupAPI"}) @Guice(modules = ApiTestModule.class) -public class WxMassMessageAPITest { +public class WxMpMassMessageAPITest { @Inject - protected WxServiceImpl wxService; + protected WxMpServiceImpl wxService; @Test public void testTextMassOpenIdsMessageSend() throws WxErrorException { // 发送群发消息 - WxXmlConfigStorage configProvider = (WxXmlConfigStorage) wxService.wxConfigStorage; - WxMassOpenIdsMessage massMessage = new WxMassOpenIdsMessage(); - massMessage.setMsgtype(WxConsts.MASS_MSG_TEXT); + ApiTestModule.WxXmlMpInMemoryConfigStorage configProvider = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.wxMpConfigStorage; + WxMpMassOpenIdsMessage massMessage = new WxMpMassOpenIdsMessage(); + massMessage.setMsgType(WxConsts.MASS_MSG_TEXT); massMessage.setContent("测试群发消息\n欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); - massMessage.getTouser().add(configProvider.getOpenId()); + massMessage.getToUsers().add(configProvider.getOpenId()); - WxMassSendResult massResult = wxService.massOpenIdsMessageSend(massMessage); + WxMpMassSendResult massResult = wxService.massOpenIdsMessageSend(massMessage); Assert.assertNotNull(massResult); - Assert.assertNotNull(massResult.getMsg_id()); + Assert.assertNotNull(massResult.getMsgId()); } @Test(dataProvider="massMessages") public void testMediaMassOpenIdsMessageSend(String massMsgType, String mediaId) throws WxErrorException, IOException { // 发送群发消息 - WxXmlConfigStorage configProvider = (WxXmlConfigStorage) wxService.wxConfigStorage; - WxMassOpenIdsMessage massMessage = new WxMassOpenIdsMessage(); - massMessage.setMsgtype(massMsgType); - massMessage.setMedia_id(mediaId); - massMessage.getTouser().add(configProvider.getOpenId()); + ApiTestModule.WxXmlMpInMemoryConfigStorage configProvider = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.wxMpConfigStorage; + WxMpMassOpenIdsMessage massMessage = new WxMpMassOpenIdsMessage(); + massMessage.setMsgType(massMsgType); + massMessage.setMediaId(mediaId); + massMessage.getToUsers().add(configProvider.getOpenId()); - WxMassSendResult massResult = wxService.massOpenIdsMessageSend(massMessage); + WxMpMassSendResult massResult = wxService.massOpenIdsMessageSend(massMessage); Assert.assertNotNull(massResult); - Assert.assertNotNull(massResult.getMsg_id()); + Assert.assertNotNull(massResult.getMsgId()); } @Test public void testTextMassGroupMessageSend() throws WxErrorException { - WxMassGroupMessage massMessage = new WxMassGroupMessage(); + WxMpMassGroupMessage massMessage = new WxMpMassGroupMessage(); massMessage.setMsgtype(WxConsts.MASS_MSG_TEXT); massMessage.setContent("测试群发消息\n欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); - massMessage.setGroup_id(wxService.groupGet().get(0).getId()); + massMessage.setGroupId(wxService.groupGet().get(0).getId()); - WxMassSendResult massResult = wxService.massGroupMessageSend(massMessage); + WxMpMassSendResult massResult = wxService.massGroupMessageSend(massMessage); Assert.assertNotNull(massResult); - Assert.assertNotNull(massResult.getMsg_id()); + Assert.assertNotNull(massResult.getMsgId()); } @Test(dataProvider="massMessages") public void testMediaMassGroupMessageSend(String massMsgType, String mediaId) throws WxErrorException, IOException { - WxMassGroupMessage massMessage = new WxMassGroupMessage(); + WxMpMassGroupMessage massMessage = new WxMpMassGroupMessage(); massMessage.setMsgtype(massMsgType); - massMessage.setMedia_id(mediaId); - massMessage.setGroup_id(wxService.groupGet().get(0).getId()); + massMessage.setMediaId(mediaId); + massMessage.setGroupId(wxService.groupGet().get(0).getId()); - WxMassSendResult massResult = wxService.massGroupMessageSend(massMessage); + WxMpMassSendResult massResult = wxService.massGroupMessageSend(massMessage); Assert.assertNotNull(massResult); - Assert.assertNotNull(massResult.getMsg_id()); + Assert.assertNotNull(massResult.getMsgId()); } @DataProvider @@ -96,17 +95,17 @@ public class WxMassMessageAPITest { InputStream inputStream = ClassLoader.getSystemResourceAsStream("mm.mp4"); WxMediaUploadResult uploadMediaRes = wxService.mediaUpload(WxConsts.MEDIA_VIDEO, WxConsts.FILE_MP4, inputStream); Assert.assertNotNull(uploadMediaRes); - Assert.assertNotNull(uploadMediaRes.getMedia_id()); + Assert.assertNotNull(uploadMediaRes.getMediaId()); // 把视频变成可被群发的媒体 - WxMassVideo video = new WxMassVideo(); + WxMpMassVideo video = new WxMpMassVideo(); video.setTitle("测试标题"); video.setDescription("测试描述"); - video.setMedia_id(uploadMediaRes.getMedia_id()); - WxMassUploadResult uploadResult = wxService.massVideoUpload(video); + video.setMediaId(uploadMediaRes.getMediaId()); + WxMpMassUploadResult uploadResult = wxService.massVideoUpload(video); Assert.assertNotNull(uploadResult); - Assert.assertNotNull(uploadResult.getMedia_id()); - messages[0] = new Object[] { WxConsts.MASS_MSG_VIDEO, uploadResult.getMedia_id() }; + Assert.assertNotNull(uploadResult.getMediaId()); + messages[0] = new Object[] { WxConsts.MASS_MSG_VIDEO, uploadResult.getMediaId() }; } /** * 图片素材 @@ -115,8 +114,8 @@ public class WxMassMessageAPITest { InputStream inputStream = ClassLoader.getSystemResourceAsStream("mm.jpeg"); WxMediaUploadResult uploadMediaRes = wxService.mediaUpload(WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, inputStream); Assert.assertNotNull(uploadMediaRes); - Assert.assertNotNull(uploadMediaRes.getMedia_id()); - messages[1] = new Object[] { WxConsts.MASS_MSG_IMAGE, uploadMediaRes.getMedia_id() }; + Assert.assertNotNull(uploadMediaRes.getMediaId()); + messages[1] = new Object[] { WxConsts.MASS_MSG_IMAGE, uploadMediaRes.getMediaId() }; } /** * 语音素材 @@ -125,8 +124,8 @@ public class WxMassMessageAPITest { InputStream inputStream = ClassLoader.getSystemResourceAsStream("mm.mp3"); WxMediaUploadResult uploadMediaRes = wxService.mediaUpload(WxConsts.MEDIA_VOICE, WxConsts.FILE_MP3, inputStream); Assert.assertNotNull(uploadMediaRes); - Assert.assertNotNull(uploadMediaRes.getMedia_id()); - messages[2] = new Object[] { WxConsts.MASS_MSG_VOICE, uploadMediaRes.getMedia_id() }; + Assert.assertNotNull(uploadMediaRes.getMediaId()); + messages[2] = new Object[] { WxConsts.MASS_MSG_VOICE, uploadMediaRes.getMediaId() }; } /** * 图文素材 @@ -136,30 +135,30 @@ public class WxMassMessageAPITest { InputStream inputStream = ClassLoader.getSystemResourceAsStream("mm.jpeg"); WxMediaUploadResult uploadMediaRes = wxService.mediaUpload(WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, inputStream); Assert.assertNotNull(uploadMediaRes); - Assert.assertNotNull(uploadMediaRes.getMedia_id()); + Assert.assertNotNull(uploadMediaRes.getMediaId()); // 上传图文消息 - WxMassNews news = new WxMassNews(); - WxMassNewsArticle article1 = new WxMassNewsArticle(); + WxMpMassNews news = new WxMpMassNews(); + WxMpMassNews.WxMpMassNewsArticle article1 = new WxMpMassNews.WxMpMassNewsArticle(); article1.setTitle("标题1"); article1.setContent("内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1"); - article1.setThumb_media_id(uploadMediaRes.getMedia_id()); + article1.setThumbMediaId(uploadMediaRes.getMediaId()); news.addArticle(article1); - WxMassNewsArticle article2 = new WxMassNewsArticle(); + WxMpMassNews.WxMpMassNewsArticle article2 = new WxMpMassNews.WxMpMassNewsArticle(); article2.setTitle("标题2"); article2.setContent("内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2"); - article2.setThumb_media_id(uploadMediaRes.getMedia_id()); - article2.setShow_cover_pic(true); + article2.setThumbMediaId(uploadMediaRes.getMediaId()); + article2.setShowCoverPic(true); article2.setAuthor("作者2"); - article2.setContent_source_url("www.baidu.com"); + article2.setContentSourceUrl("www.baidu.com"); article2.setDigest("摘要2"); news.addArticle(article2); - WxMassUploadResult massUploadResult = wxService.massNewsUpload(news); + WxMpMassUploadResult massUploadResult = wxService.massNewsUpload(news); Assert.assertNotNull(massUploadResult); - Assert.assertNotNull(uploadMediaRes.getMedia_id()); - messages[3] = new Object[] { WxConsts.MASS_MSG_NEWS, massUploadResult.getMedia_id() }; + Assert.assertNotNull(uploadMediaRes.getMediaId()); + messages[3] = new Object[] { WxConsts.MASS_MSG_NEWS, massUploadResult.getMediaId() }; } return messages; } diff --git a/src/test/java/me/chanjar/weixin/api/WxMediaAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMediaAPITest.java similarity index 75% rename from src/test/java/me/chanjar/weixin/api/WxMediaAPITest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMediaAPITest.java index ff5ec5fa..e012df40 100644 --- a/src/test/java/me/chanjar/weixin/api/WxMediaAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMediaAPITest.java @@ -1,17 +1,18 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.mp.api; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Guice; import org.testng.annotations.Test; -import me.chanjar.weixin.bean.result.WxMediaUploadResult; -import me.chanjar.weixin.exception.WxErrorException; +import me.chanjar.weixin.common.exception.WxErrorException; import com.google.inject.Inject; @@ -22,10 +23,10 @@ import com.google.inject.Inject; */ @Test(groups="mediaAPI", dependsOnGroups="baseAPI") @Guice(modules = ApiTestModule.class) -public class WxMediaAPITest { +public class WxMpMediaAPITest { @Inject - protected WxServiceImpl wxService; + protected WxMpServiceImpl wxService; private List media_ids = new ArrayList(); @@ -34,14 +35,14 @@ public class WxMediaAPITest { InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName); WxMediaUploadResult res = wxService.mediaUpload(mediaType, fileType, inputStream); Assert.assertNotNull(res.getType()); - Assert.assertNotNull(res.getCreated_at()); - Assert.assertTrue(res.getMedia_id() != null || res.getThumb_media_id() != null); + Assert.assertNotNull(res.getCreatedAt()); + Assert.assertTrue(res.getMediaId() != null || res.getThumbMediaId() != null); - if (res.getMedia_id() != null) { - media_ids.add(res.getMedia_id()); + if (res.getMediaId() != null) { + media_ids.add(res.getMediaId()); } - if (res.getThumb_media_id() != null) { - media_ids.add(res.getThumb_media_id()); + if (res.getThumbMediaId() != null) { + media_ids.add(res.getThumbMediaId()); } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMenuAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMenuAPITest.java new file mode 100644 index 00000000..335442b7 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMenuAPITest.java @@ -0,0 +1,92 @@ +package me.chanjar.weixin.mp.api; + +import javax.xml.bind.JAXBException; + +import me.chanjar.weixin.common.api.WxConsts; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import com.google.inject.Inject; + +import me.chanjar.weixin.common.bean.WxMenu; +import me.chanjar.weixin.common.bean.WxMenu.WxMenuButton; +import me.chanjar.weixin.common.exception.WxErrorException; + +/** + * 测试菜单 + * @author chanjarster + * + */ +@Test(groups="menuAPI", dependsOnGroups="baseAPI") +@Guice(modules = ApiTestModule.class) +public class WxMpMenuAPITest { + + @Inject + protected WxMpServiceImpl wxService; + + @Test(dataProvider = "menu") + public void testCreateMenu(WxMenu wxMenu) throws WxErrorException { + wxService.menuCreate(wxMenu); + } + + @Test(dependsOnMethods = { "testCreateMenu"}) + public void testGetMenu() throws WxErrorException { + Assert.assertNotNull(wxService.menuGet()); + } + + @Test(dependsOnMethods = { "testGetMenu"}) + public void testDeleteMenu() throws WxErrorException { + wxService.menuDelete(); + } + + @DataProvider(name="menu") + public Object[][] getMenu() throws JAXBException { + WxMenu menu = new WxMenu(); + WxMenuButton button1 = new WxMenuButton(); + button1.setType(WxConsts.BUTTON_CLICK); + button1.setName("今日歌曲"); + button1.setKey("V1001_TODAY_MUSIC"); + + WxMenuButton button2 = new WxMenuButton(); + button2.setType(WxConsts.BUTTON_CLICK); + button2.setName("歌手简介"); + button2.setKey("V1001_TODAY_SINGER"); + + WxMenuButton button3 = new WxMenuButton(); + button3.setName("菜单"); + + menu.getButtons().add(button1); + menu.getButtons().add(button2); + menu.getButtons().add(button3); + + WxMenuButton button31 = new WxMenuButton(); + button31.setType(WxConsts.BUTTON_VIEW); + button31.setName("搜索"); + button31.setUrl("http://www.soso.com/"); + + WxMenuButton button32 = new WxMenuButton(); + button32.setType(WxConsts.BUTTON_VIEW); + button32.setName("视频"); + button32.setUrl("http://v.qq.com/"); + + WxMenuButton button33 = new WxMenuButton(); + button33.setType(WxConsts.BUTTON_CLICK); + button33.setName("赞一下我们"); + button33.setKey("V1001_GOOD"); + + button3.getSubButtons().add(button31); + button3.getSubButtons().add(button32); + button3.getSubButtons().add(button33); + + return new Object[][] { + new Object[] { + menu + } + }; + + } + + +} diff --git a/src/test/java/me/chanjar/weixin/api/WxMessageRouterTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java similarity index 59% rename from src/test/java/me/chanjar/weixin/api/WxMessageRouterTest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java index 50423a1a..b43ca3c8 100644 --- a/src/test/java/me/chanjar/weixin/api/WxMessageRouterTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java @@ -1,65 +1,62 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.mp.api; import java.util.Map; -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.api.WxMessageHandler; -import me.chanjar.weixin.api.WxMessageRouter; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import me.chanjar.weixin.bean.WxXmlMessage; -import me.chanjar.weixin.bean.WxXmlOutMessage; - /** * 测试消息路由器 * @author chanjarster * */ @Test -public class WxMessageRouterTest { +public class WxMpMessageRouterTest { @Test(enabled = false) - public void prepare(boolean async, StringBuffer sb, WxMessageRouter router) { + public void prepare(boolean async, StringBuffer sb, WxMpMessageRouter router) { router .rule() .async(async) .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1").content("CONTENT_1") - .handler(new WxEchoMessageHandler(sb, "COMBINE_4")) + .handler(new WxEchoMpMessageHandler(sb, "COMBINE_4")) .end() .rule() .async(async) .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1") - .handler(new WxEchoMessageHandler(sb, "COMBINE_3")) + .handler(new WxEchoMpMessageHandler(sb, "COMBINE_3")) .end() .rule() .async(async) .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK) - .handler(new WxEchoMessageHandler(sb, "COMBINE_2")) + .handler(new WxEchoMpMessageHandler(sb, "COMBINE_2")) .end() - .rule().async(async).msgType(WxConsts.XML_MSG_TEXT).handler(new WxEchoMessageHandler(sb, WxConsts.XML_MSG_TEXT)).end() - .rule().async(async).event(WxConsts.EVT_CLICK).handler(new WxEchoMessageHandler(sb, WxConsts.EVT_CLICK)).end() - .rule().async(async).eventKey("KEY_1").handler(new WxEchoMessageHandler(sb, "KEY_1")).end() - .rule().async(async).content("CONTENT_1").handler(new WxEchoMessageHandler(sb, "CONTENT_1")).end() - .rule().async(async).rContent(".*bc.*").handler(new WxEchoMessageHandler(sb, "abcd")).end() - .rule().async(async).handler(new WxEchoMessageHandler(sb, "ALL")).end(); + .rule().async(async).msgType(WxConsts.XML_MSG_TEXT).handler(new WxEchoMpMessageHandler(sb, WxConsts.XML_MSG_TEXT)).end() + .rule().async(async).event(WxConsts.EVT_CLICK).handler(new WxEchoMpMessageHandler(sb, WxConsts.EVT_CLICK)).end() + .rule().async(async).eventKey("KEY_1").handler(new WxEchoMpMessageHandler(sb, "KEY_1")).end() + .rule().async(async).content("CONTENT_1").handler(new WxEchoMpMessageHandler(sb, "CONTENT_1")).end() + .rule().async(async).rContent(".*bc.*").handler(new WxEchoMpMessageHandler(sb, "abcd")).end() + .rule().async(async).handler(new WxEchoMpMessageHandler(sb, "ALL")).end(); ; } @Test(dataProvider="messages-1") - public void testSync(WxXmlMessage message, String expected) { + public void testSync(WxMpXmlMessage message, String expected) { StringBuffer sb = new StringBuffer(); - WxMessageRouter router = new WxMessageRouter(); + WxMpMessageRouter router = new WxMpMessageRouter(); prepare(false, sb, router); router.route(message); Assert.assertEquals(sb.toString(), expected); } @Test(dataProvider="messages-1") - public void testAsync(WxXmlMessage message, String expected) throws InterruptedException { + public void testAsync(WxMpXmlMessage message, String expected) throws InterruptedException { StringBuffer sb = new StringBuffer(); - WxMessageRouter router = new WxMessageRouter(); + WxMpMessageRouter router = new WxMpMessageRouter(); prepare(true, sb, router); router.route(message); Thread.sleep(500l); @@ -67,16 +64,15 @@ public class WxMessageRouterTest { } public void testConcurrency() throws InterruptedException { - final WxMessageRouter router = new WxMessageRouter(); - router.rule().handler(new WxMessageHandler() { + final WxMpMessageRouter router = new WxMpMessageRouter(); + router.rule().handler(new WxMpMessageHandler() { @Override - public WxXmlOutMessage handle(WxXmlMessage wxMessage, Map context) { - System.out.println(wxMessage.toString()); + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context) { return null; } }).end(); - final WxXmlMessage m = new WxXmlMessage(); + final WxMpXmlMessage m = new WxMpXmlMessage(); Runnable r = new Runnable() { @Override public void run() { @@ -95,34 +91,34 @@ public class WxMessageRouterTest { } @DataProvider(name="messages-1") public Object[][] messages2() { - WxXmlMessage message1 = new WxXmlMessage(); + WxMpXmlMessage message1 = new WxMpXmlMessage(); message1.setMsgType(WxConsts.XML_MSG_TEXT); - WxXmlMessage message2 = new WxXmlMessage(); + WxMpXmlMessage message2 = new WxMpXmlMessage(); message2.setEvent(WxConsts.EVT_CLICK); - WxXmlMessage message3 = new WxXmlMessage(); + WxMpXmlMessage message3 = new WxMpXmlMessage(); message3.setEventKey("KEY_1"); - WxXmlMessage message4 = new WxXmlMessage(); + WxMpXmlMessage message4 = new WxMpXmlMessage(); message4.setContent("CONTENT_1"); - WxXmlMessage message5 = new WxXmlMessage(); + WxMpXmlMessage message5 = new WxMpXmlMessage(); message5.setContent("BLA"); - WxXmlMessage message6 = new WxXmlMessage(); + WxMpXmlMessage message6 = new WxMpXmlMessage(); message6.setContent("abcd"); - WxXmlMessage c2 = new WxXmlMessage(); + WxMpXmlMessage c2 = new WxMpXmlMessage(); c2.setMsgType(WxConsts.XML_MSG_TEXT); c2.setEvent(WxConsts.EVT_CLICK); - WxXmlMessage c3 = new WxXmlMessage(); + WxMpXmlMessage c3 = new WxMpXmlMessage(); c3.setMsgType(WxConsts.XML_MSG_TEXT); c3.setEvent(WxConsts.EVT_CLICK); c3.setEventKey("KEY_1"); - WxXmlMessage c4 = new WxXmlMessage(); + WxMpXmlMessage c4 = new WxMpXmlMessage(); c4.setMsgType(WxConsts.XML_MSG_TEXT); c4.setEvent(WxConsts.EVT_CLICK); c4.setEventKey("KEY_1"); @@ -130,7 +126,7 @@ public class WxMessageRouterTest { return new Object[][] { new Object[] { message1, WxConsts.XML_MSG_TEXT + "," }, - new Object[] { message2, WxConsts.EVT_CLICK + "," }, + new Object[] { message2, WxConsts.EVT_CLICK + "," }, new Object[] { message3, "KEY_1," }, new Object[] { message4, "CONTENT_1," }, new Object[] { message5, "ALL," }, @@ -142,18 +138,18 @@ public class WxMessageRouterTest { } - public static class WxEchoMessageHandler implements WxMessageHandler { + public static class WxEchoMpMessageHandler implements WxMpMessageHandler { private StringBuffer sb; private String echoStr; - public WxEchoMessageHandler(StringBuffer sb, String echoStr) { + public WxEchoMpMessageHandler(StringBuffer sb, String echoStr) { this.sb = sb; this.echoStr = echoStr; } @Override - public WxXmlOutMessage handle(WxXmlMessage wxMessage, Map context) { + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context) { sb.append(this.echoStr).append(','); return null; } diff --git a/src/test/java/me/chanjar/weixin/api/WxQrCodeAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpQrCodeAPITest.java similarity index 68% rename from src/test/java/me/chanjar/weixin/api/WxQrCodeAPITest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpQrCodeAPITest.java index 1c07072f..2a206d2e 100644 --- a/src/test/java/me/chanjar/weixin/api/WxQrCodeAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpQrCodeAPITest.java @@ -1,13 +1,13 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.mp.api; import java.io.File; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; import org.testng.Assert; import org.testng.annotations.Guice; import org.testng.annotations.Test; -import me.chanjar.weixin.bean.result.WxQrCodeTicket; -import me.chanjar.weixin.exception.WxErrorException; +import me.chanjar.weixin.common.exception.WxErrorException; import com.google.inject.Inject; @@ -18,27 +18,27 @@ import com.google.inject.Inject; */ @Test(groups = "qrCodeAPI", dependsOnGroups = { "baseAPI" }) @Guice(modules = ApiTestModule.class) -public class WxQrCodeAPITest { +public class WxMpQrCodeAPITest { @Inject - protected WxServiceImpl wxService; + protected WxMpServiceImpl wxService; public void testQrCodeCreateTmpTicket() throws WxErrorException { - WxQrCodeTicket ticket = wxService.qrCodeCreateTmpTicket(1, null); + WxMpQrCodeTicket ticket = wxService.qrCodeCreateTmpTicket(1, null); Assert.assertNotNull(ticket.getUrl()); Assert.assertNotNull(ticket.getTicket()); Assert.assertTrue(ticket.getExpire_seconds() != -1); } public void testQrCodeCreateLastTicket() throws WxErrorException { - WxQrCodeTicket ticket = wxService.qrCodeCreateLastTicket(1); + WxMpQrCodeTicket ticket = wxService.qrCodeCreateLastTicket(1); Assert.assertNotNull(ticket.getUrl()); Assert.assertNotNull(ticket.getTicket()); Assert.assertTrue(ticket.getExpire_seconds() == -1); } public void testQrCodePicture() throws WxErrorException { - WxQrCodeTicket ticket = wxService.qrCodeCreateLastTicket(1); + WxMpQrCodeTicket ticket = wxService.qrCodeCreateLastTicket(1); File file = wxService.qrCodePicture(ticket); Assert.assertNotNull(file); } diff --git a/src/test/java/me/chanjar/weixin/api/WxShortUrlAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpShortUrlAPITest.java similarity index 73% rename from src/test/java/me/chanjar/weixin/api/WxShortUrlAPITest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpShortUrlAPITest.java index 3df6e217..e854ed08 100644 --- a/src/test/java/me/chanjar/weixin/api/WxShortUrlAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpShortUrlAPITest.java @@ -1,10 +1,10 @@ -package me.chanjar.weixin.api; +package me.chanjar.weixin.mp.api; import org.testng.Assert; import org.testng.annotations.Guice; import org.testng.annotations.Test; -import me.chanjar.weixin.exception.WxErrorException; +import me.chanjar.weixin.common.exception.WxErrorException; import com.google.inject.Inject; @@ -15,10 +15,10 @@ import com.google.inject.Inject; */ @Test(groups = "shortURLAPI", dependsOnGroups = { "baseAPI" }) @Guice(modules = ApiTestModule.class) -public class WxShortUrlAPITest { +public class WxMpShortUrlAPITest { @Inject - protected WxServiceImpl wxService; + protected WxMpServiceImpl wxService; public void testShortUrl() throws WxErrorException { String shortUrl = wxService.shortUrl("www.baidu.com"); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpUserAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpUserAPITest.java new file mode 100644 index 00000000..c29bda83 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpUserAPITest.java @@ -0,0 +1,55 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.mp.bean.result.WxMpUserList; +import org.testng.Assert; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import me.chanjar.weixin.common.exception.WxErrorException; + +import com.google.inject.Inject; + +/** + * 测试用户相关的接口 + * @author chanjarster + * + */ +@Test(groups = "userAPI", dependsOnGroups = { "baseAPI", "groupAPI" }) +@Guice(modules = ApiTestModule.class) +public class WxMpUserAPITest { + + @Inject + protected WxMpServiceImpl wxService; + + public void testUserUpdateRemark() throws WxErrorException { + ApiTestModule.WxXmlMpInMemoryConfigStorage configProvider = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.wxMpConfigStorage; + wxService.userUpdateRemark(configProvider.getOpenId(), "测试备注名"); + } + + public void testUserInfo() throws WxErrorException { + ApiTestModule.WxXmlMpInMemoryConfigStorage configProvider = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.wxMpConfigStorage; + WxMpUser user = wxService.userInfo(configProvider.getOpenId(), null); + Assert.assertNotNull(user); + } + + public void testUserList() throws WxErrorException { + WxMpUserList wxMpUserList = wxService.userList(null); + Assert.assertNotNull(wxMpUserList); + Assert.assertFalse(wxMpUserList.getCount() == -1); + Assert.assertFalse(wxMpUserList.getTotal() == -1); + Assert.assertFalse(wxMpUserList.getOpenIds().size() == -1); + } + + public void testGroupQueryUserGroup() throws WxErrorException { + ApiTestModule.WxXmlMpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.wxMpConfigStorage; + long groupid = wxService.userGetGroup(configStorage.getOpenId()); + Assert.assertTrue(groupid != -1l); + } + + public void getGroupMoveUser() throws WxErrorException { + ApiTestModule.WxXmlMpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlMpInMemoryConfigStorage) wxService.wxMpConfigStorage; + wxService.userUpdateGroup(configStorage.getOpenId(), wxService.groupGet().get(3).getId()); + } + +} diff --git a/src/test/java/me/chanjar/weixin/bean/WxCustomMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpCustomMessageTest.java similarity index 65% rename from src/test/java/me/chanjar/weixin/bean/WxCustomMessageTest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpCustomMessageTest.java index d96e928b..68947b41 100644 --- a/src/test/java/me/chanjar/weixin/bean/WxCustomMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpCustomMessageTest.java @@ -1,109 +1,108 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.mp.bean; -import me.chanjar.weixin.bean.WxCustomMessage; +import me.chanjar.weixin.common.api.WxConsts; import org.testng.Assert; import org.testng.annotations.Test; -import me.chanjar.weixin.api.WxConsts; -import me.chanjar.weixin.bean.WxCustomMessage.WxArticle; +import me.chanjar.weixin.mp.bean.WxMpCustomMessage.WxArticle; @Test -public class WxCustomMessageTest { +public class WxMpCustomMessageTest { public void testTextReply() { - WxCustomMessage reply = new WxCustomMessage(); - reply.setTouser("OPENID"); - reply.setMsgtype(WxConsts.CUSTOM_MSG_TEXT); + WxMpCustomMessage reply = new WxMpCustomMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxConsts.CUSTOM_MSG_TEXT); reply.setContent("sfsfdsdf"); Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); } public void testTextBuild() { - WxCustomMessage reply = WxCustomMessage.TEXT().toUser("OPENID").content("sfsfdsdf").build(); + WxMpCustomMessage reply = WxMpCustomMessage.TEXT().toUser("OPENID").content("sfsfdsdf").build(); Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); } public void testImageReply() { - WxCustomMessage reply = new WxCustomMessage(); - reply.setTouser("OPENID"); - reply.setMsgtype(WxConsts.CUSTOM_MSG_IMAGE); - reply.setMedia_id("MEDIA_ID"); + WxMpCustomMessage reply = new WxMpCustomMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxConsts.CUSTOM_MSG_IMAGE); + reply.setMediaId("MEDIA_ID"); Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); } public void testImageBuild() { - WxCustomMessage reply = WxCustomMessage.IMAGE().toUser("OPENID").mediaId("MEDIA_ID").build(); + WxMpCustomMessage reply = WxMpCustomMessage.IMAGE().toUser("OPENID").mediaId("MEDIA_ID").build(); Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); } public void testVoiceReply() { - WxCustomMessage reply = new WxCustomMessage(); - reply.setTouser("OPENID"); - reply.setMsgtype(WxConsts.CUSTOM_MSG_VOICE); - reply.setMedia_id("MEDIA_ID"); + WxMpCustomMessage reply = new WxMpCustomMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxConsts.CUSTOM_MSG_VOICE); + reply.setMediaId("MEDIA_ID"); Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"voice\",\"voice\":{\"media_id\":\"MEDIA_ID\"}}"); } public void testVoiceBuild() { - WxCustomMessage reply = WxCustomMessage.VOICE().toUser("OPENID").mediaId("MEDIA_ID").build(); + WxMpCustomMessage reply = WxMpCustomMessage.VOICE().toUser("OPENID").mediaId("MEDIA_ID").build(); Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"voice\",\"voice\":{\"media_id\":\"MEDIA_ID\"}}"); } public void testVideoReply() { - WxCustomMessage reply = new WxCustomMessage(); - reply.setTouser("OPENID"); - reply.setMsgtype(WxConsts.CUSTOM_MSG_VIDEO); - reply.setMedia_id("MEDIA_ID"); - reply.setThumb_media_id("MEDIA_ID"); + WxMpCustomMessage reply = new WxMpCustomMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxConsts.CUSTOM_MSG_VIDEO); + reply.setMediaId("MEDIA_ID"); + reply.setThumbMediaId("MEDIA_ID"); reply.setTitle("TITLE"); reply.setDescription("DESCRIPTION"); Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"video\",\"video\":{\"media_id\":\"MEDIA_ID\",\"thumb_media_id\":\"MEDIA_ID\",\"title\":\"TITLE\",\"description\":\"DESCRIPTION\"}}"); } public void testVideoBuild() { - WxCustomMessage reply = WxCustomMessage.VIDEO().toUser("OPENID").title("TITLE").mediaId("MEDIA_ID").thumbMediaId("MEDIA_ID").description("DESCRIPTION").build(); + WxMpCustomMessage reply = WxMpCustomMessage.VIDEO().toUser("OPENID").title("TITLE").mediaId("MEDIA_ID").thumbMediaId("MEDIA_ID").description("DESCRIPTION").build(); Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"video\",\"video\":{\"media_id\":\"MEDIA_ID\",\"thumb_media_id\":\"MEDIA_ID\",\"title\":\"TITLE\",\"description\":\"DESCRIPTION\"}}"); } public void testMusicReply() { - WxCustomMessage reply = new WxCustomMessage(); - reply.setTouser("OPENID"); - reply.setMsgtype(WxConsts.CUSTOM_MSG_MUSIC); - reply.setThumb_media_id("MEDIA_ID"); + WxMpCustomMessage reply = new WxMpCustomMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxConsts.CUSTOM_MSG_MUSIC); + reply.setThumbMediaId("MEDIA_ID"); reply.setDescription("DESCRIPTION"); reply.setTitle("TITLE"); - reply.setMusicurl("MUSIC_URL"); - reply.setHqmusicurl("HQ_MUSIC_URL"); + reply.setMusicUrl("MUSIC_URL"); + reply.setHqMusicUrl("HQ_MUSIC_URL"); Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"music\",\"music\":{\"title\":\"TITLE\",\"description\":\"DESCRIPTION\",\"thumb_media_id\":\"MEDIA_ID\",\"musicurl\":\"MUSIC_URL\",\"hqmusicurl\":\"HQ_MUSIC_URL\"}}"); } public void testMusicBuild() { - WxCustomMessage reply = WxCustomMessage.MUSIC() + WxMpCustomMessage reply = WxMpCustomMessage.MUSIC() .toUser("OPENID") .title("TITLE") .thumbMediaId("MEDIA_ID") .description("DESCRIPTION") .musicUrl("MUSIC_URL") - .hqmusicUrl("HQ_MUSIC_URL") + .hqMusicUrl("HQ_MUSIC_URL") .build(); Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"music\",\"music\":{\"title\":\"TITLE\",\"description\":\"DESCRIPTION\",\"thumb_media_id\":\"MEDIA_ID\",\"musicurl\":\"MUSIC_URL\",\"hqmusicurl\":\"HQ_MUSIC_URL\"}}"); } public void testNewsReply() { - WxCustomMessage reply = new WxCustomMessage(); - reply.setTouser("OPENID"); - reply.setMsgtype(WxConsts.CUSTOM_MSG_NEWS); + WxMpCustomMessage reply = new WxMpCustomMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxConsts.CUSTOM_MSG_NEWS); WxArticle article1 = new WxArticle(); article1.setUrl("URL"); - article1.setPicurl("PIC_URL"); + article1.setPicUrl("PIC_URL"); article1.setDescription("Is Really A Happy Day"); article1.setTitle("Happy Day"); reply.getArticles().add(article1); WxArticle article2 = new WxArticle(); article2.setUrl("URL"); - article2.setPicurl("PIC_URL"); + article2.setPicUrl("PIC_URL"); article2.setDescription("Is Really A Happy Day"); article2.setTitle("Happy Day"); reply.getArticles().add(article2); @@ -115,17 +114,17 @@ public class WxCustomMessageTest { public void testNewsBuild() { WxArticle article1 = new WxArticle(); article1.setUrl("URL"); - article1.setPicurl("PIC_URL"); + article1.setPicUrl("PIC_URL"); article1.setDescription("Is Really A Happy Day"); article1.setTitle("Happy Day"); WxArticle article2 = new WxArticle(); article2.setUrl("URL"); - article2.setPicurl("PIC_URL"); + article2.setPicUrl("PIC_URL"); article2.setDescription("Is Really A Happy Day"); article2.setTitle("Happy Day"); - WxCustomMessage reply = WxCustomMessage.NEWS().toUser("OPENID").addArticle(article1).addArticle(article2).build(); + WxMpCustomMessage reply = WxMpCustomMessage.NEWS().toUser("OPENID").addArticle(article1).addArticle(article2).build(); Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}"); } diff --git a/src/test/java/me/chanjar/weixin/bean/WxXmlMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpXmlMessageTest.java similarity index 59% rename from src/test/java/me/chanjar/weixin/bean/WxXmlMessageTest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpXmlMessageTest.java index 79ad7634..346681cb 100644 --- a/src/test/java/me/chanjar/weixin/bean/WxXmlMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpXmlMessageTest.java @@ -1,11 +1,11 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.mp.bean; -import me.chanjar.weixin.api.WxConsts; +import me.chanjar.weixin.common.api.WxConsts; import org.testng.Assert; import org.testng.annotations.Test; @Test -public class WxXmlMessageTest { +public class WxMpXmlMessageTest { public void testFromXml() { @@ -33,8 +33,27 @@ public class WxXmlMessageTest { + "23.137466" + "113.352425" + "119.385040" + + "" + + " " + + " " + + "" + + "" + + " 1\n" + + " " + + " " + + " " + + " " + + " " + + "" + + "" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "" + ""; - WxXmlMessage wxMessage = WxXmlMessage.fromXml(xml); + WxMpXmlMessage wxMessage = WxMpXmlMessage.fromXml(xml); Assert.assertEquals(wxMessage.getToUserName(), "toUser"); Assert.assertEquals(wxMessage.getFromUserName(), "fromUser"); Assert.assertEquals(wxMessage.getCreateTime(), new Long(1348831860l)); @@ -45,8 +64,8 @@ public class WxXmlMessageTest { Assert.assertEquals(wxMessage.getMediaId(), "media_id"); Assert.assertEquals(wxMessage.getFormat(), "Format"); Assert.assertEquals(wxMessage.getThumbMediaId(), "thumb_media_id"); - Assert.assertEquals(wxMessage.getLocation_X(), new Double(23.134521d)); - Assert.assertEquals(wxMessage.getLocation_Y(), new Double(113.358803d)); + Assert.assertEquals(wxMessage.getLocationX(), new Double(23.134521d)); + Assert.assertEquals(wxMessage.getLocationY(), new Double(113.358803d)); Assert.assertEquals(wxMessage.getScale(), new Double(20)); Assert.assertEquals(wxMessage.getLabel(), "位置信息"); Assert.assertEquals(wxMessage.getDescription(), "公众平台官网链接"); @@ -58,6 +77,15 @@ public class WxXmlMessageTest { Assert.assertEquals(wxMessage.getLatitude(), new Double(23.137466)); Assert.assertEquals(wxMessage.getLongitude(), new Double(113.352425)); Assert.assertEquals(wxMessage.getPrecision(), new Double(119.385040)); + Assert.assertEquals(wxMessage.getScanCodeInfo().getScanType(), "qrcode"); + Assert.assertEquals(wxMessage.getScanCodeInfo().getScanResult(), "1"); + Assert.assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(1l)); + Assert.assertEquals(wxMessage.getSendPicsInfo().getPicList().get(0).getPicMd5Sum(), "1b5f7c23b5bf75682a53e7b6d163e185"); + Assert.assertEquals(wxMessage.getSendLocationInfo().getLocationX(), "23"); + Assert.assertEquals(wxMessage.getSendLocationInfo().getLocationY(), "113"); + Assert.assertEquals(wxMessage.getSendLocationInfo().getScale(), "15"); + Assert.assertEquals(wxMessage.getSendLocationInfo().getLabel(), " 广州市海珠区客村艺苑路 106号"); + Assert.assertEquals(wxMessage.getSendLocationInfo().getPoiname(), "wo de poi"); } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpXmlOutImageMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpXmlOutImageMessageTest.java new file mode 100644 index 00000000..e0377cb6 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpXmlOutImageMessageTest.java @@ -0,0 +1,50 @@ +package me.chanjar.weixin.mp.bean; + +import org.testng.Assert; +import org.testng.annotations.Test; + +@Test +public class WxMpXmlOutImageMessageTest { + + public void test() { + WxMpMpXmlOutImageMessage m = new WxMpMpXmlOutImageMessage(); + m.setMediaId("ddfefesfsdfef"); + m.setCreateTime(1122l); + m.setFromUserName("from"); + m.setToUserName("to"); + + String expected = "" + + "" + + "" + + "" + + "1122" + + "" + + "" + + ""; + System.out.println(m.toXml()); + Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); + } + + public void testBuild() { + WxMpMpXmlOutImageMessage m = WxMpXmlOutMessage.IMAGE().mediaId("ddfefesfsdfef").fromUser("from").toUser("to").build(); + String expected = "" + + "" + + "" + + "" + + "1122" + + "" + + "" + + ""; + System.out.println(m.toXml()); + Assert.assertEquals( + m + .toXml() + .replaceAll("\\s", "") + .replaceAll(".*?", ""), + expected + .replaceAll("\\s", "") + .replaceAll(".*?", "") + ); + + } +} diff --git a/src/test/java/me/chanjar/weixin/bean/WxXmlOutIMusicMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutMusicMessageTest.java similarity index 86% rename from src/test/java/me/chanjar/weixin/bean/WxXmlOutIMusicMessageTest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutMusicMessageTest.java index 01a78852..0471e2c3 100644 --- a/src/test/java/me/chanjar/weixin/bean/WxXmlOutIMusicMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutMusicMessageTest.java @@ -1,18 +1,16 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.mp.bean; -import me.chanjar.weixin.bean.WxXmlOutMessage; -import me.chanjar.weixin.bean.WxXmlOutMusicMessage; import org.testng.Assert; import org.testng.annotations.Test; @Test -public class WxXmlOutIMusicMessageTest { +public class WxXmlOutMusicMessageTest { public void test() { - WxXmlOutMusicMessage m = new WxXmlOutMusicMessage(); + WxMpXmlOutMusicMessage m = new WxMpXmlOutMusicMessage(); m.setTitle("title"); m.setDescription("ddfff"); - m.setHQMusicUrl("hQMusicUrl"); + m.setHqMusicUrl("hQMusicUrl"); m.setMusicUrl("musicUrl"); m.setThumbMediaId("thumbMediaId"); m.setCreateTime(1122l); @@ -38,12 +36,12 @@ public class WxXmlOutIMusicMessageTest { } public void testBuild() { - WxXmlOutMusicMessage m = WxXmlOutMessage.MUSIC() + WxMpXmlOutMusicMessage m = WxMpXmlOutMessage.MUSIC() .fromUser("fromUser") - .touser("toUser") + .toUser("toUser") .title("title") .description("ddfff") - .hqmusicUrl("hQMusicUrl") + .hqMusicUrl("hQMusicUrl") .musicUrl("musicUrl") .thumbMediaId("thumbMediaId") .build(); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutNewsMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutNewsMessageTest.java new file mode 100644 index 00000000..782a6abe --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutNewsMessageTest.java @@ -0,0 +1,95 @@ +package me.chanjar.weixin.mp.bean; + +import org.testng.Assert; +import org.testng.annotations.Test; + +@Test +public class WxXmlOutNewsMessageTest { + + public void test() { + WxMpXmlOutMewsMessage m = new WxMpXmlOutMewsMessage(); + m.setCreateTime(1122l); + m.setFromUserName("fromUser"); + m.setToUserName("toUser"); + + WxMpXmlOutMewsMessage.Item item = new WxMpXmlOutMewsMessage.Item(); + item.setDescription("description"); + item.setPicUrl("picUrl"); + item.setTitle("title"); + item.setUrl("url"); + m.addArticle(item); + m.addArticle(item); + String expected = "" + + "" + + "" + + "" + + "1122" + + "" + + " 2" + + " " + + " " + + " <![CDATA[title]]>" + + " " + + " " + + " " + + " " + + " " + + " <![CDATA[title]]>" + + " " + + " " + + " " + + " " + + " " + + ""; + System.out.println(m.toXml()); + Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); + } + + public void testBuild() { + WxMpXmlOutMewsMessage.Item item = new WxMpXmlOutMewsMessage.Item(); + item.setDescription("description"); + item.setPicUrl("picUrl"); + item.setTitle("title"); + item.setUrl("url"); + + WxMpXmlOutMewsMessage m = WxMpXmlOutMessage.NEWS() + .fromUser("fromUser") + .toUser("toUser") + .addArticle(item) + .addArticle(item) + .build(); + String expected = "" + + "" + + "" + + "" + + "1122" + + "" + + " 2" + + " " + + " " + + " <![CDATA[title]]>" + + " " + + " " + + " " + + " " + + " " + + " <![CDATA[title]]>" + + " " + + " " + + " " + + " " + + " " + + ""; + System.out.println(m.toXml()); + Assert.assertEquals( + m + .toXml() + .replaceAll("\\s", "") + .replaceAll(".*?", ""), + expected + .replaceAll("\\s", "") + .replaceAll(".*?", "") + ); + } + +} diff --git a/src/test/java/me/chanjar/weixin/bean/WxXmlOutTextMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutTextMessageTest.java similarity index 83% rename from src/test/java/me/chanjar/weixin/bean/WxXmlOutTextMessageTest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutTextMessageTest.java index b8291f99..a845abcd 100644 --- a/src/test/java/me/chanjar/weixin/bean/WxXmlOutTextMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutTextMessageTest.java @@ -1,7 +1,5 @@ -package me.chanjar.weixin.bean; +package me.chanjar.weixin.mp.bean; -import me.chanjar.weixin.bean.WxXmlOutMessage; -import me.chanjar.weixin.bean.WxXmlOutTextMessage; import org.testng.Assert; import org.testng.annotations.Test; @@ -9,7 +7,7 @@ import org.testng.annotations.Test; public class WxXmlOutTextMessageTest { public void test() { - WxXmlOutTextMessage m = new WxXmlOutTextMessage(); + WxMpXmlOutTextMessage m = new WxMpXmlOutTextMessage(); m.setContent("content"); m.setCreateTime(1122l); m.setFromUserName("from"); @@ -28,7 +26,7 @@ public class WxXmlOutTextMessageTest { } public void testBuild() { - WxXmlOutTextMessage m = WxXmlOutMessage.TEXT().content("content").fromUser("from").touser("to").build(); + WxMpXmlOutTextMessage m = WxMpXmlOutMessage.TEXT().content("content").fromUser("from").toUser("to").build(); String expected = "" + "" + "" diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutVideoMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutVideoMessageTest.java new file mode 100644 index 00000000..b033b040 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutVideoMessageTest.java @@ -0,0 +1,66 @@ +package me.chanjar.weixin.mp.bean; + +import org.testng.Assert; +import org.testng.annotations.Test; + +@Test +public class WxXmlOutVideoMessageTest { + + public void test() { + WxMpXmlOutVideoMessage m = new WxMpXmlOutVideoMessage(); + m.setMediaId("media_id"); + m.setTitle("title"); + m.setDescription("ddfff"); + m.setCreateTime(1122l); + m.setFromUserName("fromUser"); + m.setToUserName("toUser"); + + String expected = "" + + "" + + "" + + "" + + "1122" + + "" + + " " + + ""; + System.out.println(m.toXml()); + Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); + } + + public void testBuild() { + WxMpXmlOutVideoMessage m = WxMpXmlOutMessage.VIDEO() + .mediaId("media_id") + .fromUser("fromUser") + .toUser("toUser") + .title("title") + .description("ddfff") + .build(); + String expected = "" + + "" + + "" + + "" + + "1122" + + "" + + " " + + ""; + System.out.println(m.toXml()); + Assert.assertEquals( + m + .toXml() + .replaceAll("\\s", "") + .replaceAll(".*?", ""), + expected + .replaceAll("\\s", "") + .replaceAll(".*?", "") + ); + } + +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutVoiceMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutVoiceMessageTest.java new file mode 100644 index 00000000..65644f3d --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutVoiceMessageTest.java @@ -0,0 +1,50 @@ +package me.chanjar.weixin.mp.bean; + +import org.testng.Assert; +import org.testng.annotations.Test; + +@Test +public class WxXmlOutVoiceMessageTest { + + public void test() { + WxMpXmlOutVoiceMessage m = new WxMpXmlOutVoiceMessage(); + m.setMediaId("ddfefesfsdfef"); + m.setCreateTime(1122l); + m.setFromUserName("from"); + m.setToUserName("to"); + + String expected = "" + + "" + + "" + + "" + + "1122" + + "" + + "" + + ""; + System.out.println(m.toXml()); + Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); + } + + public void testBuild() { + WxMpXmlOutVoiceMessage m = WxMpXmlOutMessage.VOICE().mediaId("ddfefesfsdfef").fromUser("from").toUser("to").build(); + String expected = "" + + "" + + "" + + "" + + "1122" + + "" + + "" + + ""; + System.out.println(m.toXml()); + Assert.assertEquals( + m + .toXml() + .replaceAll("\\s", "") + .replaceAll(".*?", ""), + expected + .replaceAll("\\s", "") + .replaceAll(".*?", "") + ); + } + +} diff --git a/src/test/java/me/chanjar/weixin/demo/WxTestConfigStorage.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java similarity index 63% rename from src/test/java/me/chanjar/weixin/demo/WxTestConfigStorage.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java index d5921e0c..430d327d 100644 --- a/src/test/java/me/chanjar/weixin/demo/WxTestConfigStorage.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java @@ -1,6 +1,6 @@ -package me.chanjar.weixin.demo; +package me.chanjar.weixin.mp.demo; -import me.chanjar.weixin.api.WxInMemoryConfigStorage; +import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; import org.xml.sax.InputSource; import javax.xml.bind.JAXBContext; @@ -16,7 +16,7 @@ import java.io.InputStream; */ @XmlRootElement(name = "xml") @XmlAccessorType(XmlAccessType.FIELD) -class WxTestConfigStorage extends WxInMemoryConfigStorage { +class WxMpDemoInMemoryConfigStorage extends WxMpInMemoryConfigStorage { @Override public String toString() { @@ -25,11 +25,11 @@ class WxTestConfigStorage extends WxInMemoryConfigStorage { } - public static WxTestConfigStorage fromXml(InputStream is) throws JAXBException { - Unmarshaller um = JAXBContext.newInstance(WxTestConfigStorage.class).createUnmarshaller(); + public static WxMpDemoInMemoryConfigStorage fromXml(InputStream is) throws JAXBException { + Unmarshaller um = JAXBContext.newInstance(WxMpDemoInMemoryConfigStorage.class).createUnmarshaller(); InputSource inputSource = new InputSource(is); inputSource.setEncoding("utf-8"); - return (WxTestConfigStorage) um.unmarshal(inputSource); + return (WxMpDemoInMemoryConfigStorage) um.unmarshal(inputSource); } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java new file mode 100644 index 00000000..e0bb6498 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java @@ -0,0 +1,20 @@ +package me.chanjar.weixin.mp.demo; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; + +/** + * @author Daniel Qian + */ +public class WxMpDemoServer { + public static void main(String[] args) throws Exception { + Server server = new Server(8080); + + ServletHandler handler = new ServletHandler(); + server.setHandler(handler); + + handler.addServletWithMapping(WxMpDemoServlet.class, "/*"); + server.start(); + server.join(); + } +} diff --git a/src/test/java/me/chanjar/weixin/demo/WxTestServlet.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServlet.java similarity index 59% rename from src/test/java/me/chanjar/weixin/demo/WxTestServlet.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServlet.java index 40f8ad7c..7ceb2e26 100644 --- a/src/test/java/me/chanjar/weixin/demo/WxTestServlet.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServlet.java @@ -1,9 +1,9 @@ -package me.chanjar.weixin.demo; +package me.chanjar.weixin.mp.demo; -import me.chanjar.weixin.api.*; -import me.chanjar.weixin.bean.WxXmlMessage; -import me.chanjar.weixin.bean.WxXmlOutMessage; -import me.chanjar.weixin.bean.WxXmlOutTextMessage; +import me.chanjar.weixin.mp.api.*; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutTextMessage; import org.apache.commons.lang3.StringUtils; import javax.servlet.ServletException; @@ -18,34 +18,34 @@ import java.util.Map; /** * @author Daniel Qian */ -public class WxTestServlet extends HttpServlet { +public class WxMpDemoServlet extends HttpServlet { - protected WxService wxService; - protected WxConfigStorage wxConfigStorage; - protected WxMessageRouter wxMessageRouter; + protected WxMpService wxMpService; + protected WxMpConfigStorage wxMpConfigStorage; + protected WxMpMessageRouter wxMpMessageRouter; @Override public void init() throws ServletException { // super.init(); try { InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml"); - WxTestConfigStorage config = WxTestConfigStorage.fromXml(is1); + WxMpDemoInMemoryConfigStorage config = WxMpDemoInMemoryConfigStorage.fromXml(is1); - wxConfigStorage = config; - wxService = new WxServiceImpl(); - wxService.setWxConfigStorage(config); + wxMpConfigStorage = config; + wxMpService = new WxMpServiceImpl(); + wxMpService.setWxMpConfigStorage(config); - WxMessageHandler handler = new WxMessageHandler() { - @Override public WxXmlOutMessage handle(WxXmlMessage wxMessage, Map context) { - WxXmlOutTextMessage m - = WxXmlOutMessage.TEXT().content("测试加密消息").fromUser(wxMessage.getToUserName()) - .touser(wxMessage.getFromUserName()).build(); + WxMpMessageHandler handler = new WxMpMessageHandler() { + @Override public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context) { + WxMpXmlOutTextMessage m + = WxMpXmlOutMessage.TEXT().content("测试加密消息").fromUser(wxMessage.getToUserName()) + .toUser(wxMessage.getFromUserName()).build(); return m; } }; - wxMessageRouter = new WxMessageRouter(); - wxMessageRouter + wxMpMessageRouter = new WxMpMessageRouter(); + wxMpMessageRouter .rule() .async(false) .content("哈哈") // 拦截内容为“哈哈”的消息 @@ -67,7 +67,7 @@ public class WxTestServlet extends HttpServlet { response.setContentType("text/html;charset=utf-8"); response.setStatus(HttpServletResponse.SC_OK); - if (!wxService.checkSignature(timestamp, nonce, signature)) { + if (!wxMpService.checkSignature(timestamp, nonce, signature)) { // 消息签名不正确,说明不是公众平台发过来的消息 response.getWriter().println("非法请求"); return; @@ -84,30 +84,27 @@ public class WxTestServlet extends HttpServlet { "raw" : request.getParameter("encrypt_type"); - WxXmlMessage inMessage = null; + WxMpXmlMessage inMessage = null; if ("raw".equals(encryptType)) { // 明文传输的消息 - inMessage = WxXmlMessage.fromXml(request.getInputStream()); + inMessage = WxMpXmlMessage.fromXml(request.getInputStream()); } else if ("aes".equals(encryptType)) { // 是aes加密的消息 String msgSignature = request.getParameter("msg_signature"); - inMessage = WxXmlMessage.fromEncryptedXml( - request.getInputStream(), - wxConfigStorage, - timestamp, nonce, msgSignature); + inMessage = WxMpXmlMessage.fromEncryptedXml(request.getInputStream(), wxMpConfigStorage, timestamp, nonce, msgSignature); } else { response.getWriter().println("不可识别的加密类型"); return; } - WxXmlOutMessage outMessage = wxMessageRouter.route(inMessage); + WxMpXmlOutMessage outMessage = wxMpMessageRouter.route(inMessage); if (outMessage != null) { if ("raw".equals(encryptType)) { response.getWriter().write(outMessage.toXml()); } else if ("aes".equals(encryptType)) { - response.getWriter().write(outMessage.toEncryptedXml(wxConfigStorage)); + response.getWriter().write(outMessage.toEncryptedXml(wxMpConfigStorage)); } return; } diff --git a/weixin-java-mp/src/test/resources/mm.jpeg b/weixin-java-mp/src/test/resources/mm.jpeg new file mode 100644 index 00000000..183699e9 Binary files /dev/null and b/weixin-java-mp/src/test/resources/mm.jpeg differ diff --git a/weixin-java-mp/src/test/resources/mm.mp3 b/weixin-java-mp/src/test/resources/mm.mp3 new file mode 100644 index 00000000..d818e510 Binary files /dev/null and b/weixin-java-mp/src/test/resources/mm.mp3 differ diff --git a/weixin-java-mp/src/test/resources/mm.mp4 b/weixin-java-mp/src/test/resources/mm.mp4 new file mode 100644 index 00000000..ff74317a Binary files /dev/null and b/weixin-java-mp/src/test/resources/mm.mp4 differ diff --git a/src/test/resources/test-config.sample.xml b/weixin-java-mp/src/test/resources/test-config.sample.xml similarity index 100% rename from src/test/resources/test-config.sample.xml rename to weixin-java-mp/src/test/resources/test-config.sample.xml diff --git a/weixin-java-mp/src/test/resources/testng.xml b/weixin-java-mp/src/test/resources/testng.xml new file mode 100644 index 00000000..8987f762 --- /dev/null +++ b/weixin-java-mp/src/test/resources/testng.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +