From 0ca9a5a9f41f30871737a97a21d1ae81b60f7cc1 Mon Sep 17 00:00:00 2001 From: "jy.hu" Date: Sat, 31 Jan 2015 00:33:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=95=B0=E6=8D=AE=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1=E6=8E=A5=E5=8F=A3&=E6=94=AF=E4=BB=98=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/foxinmy/weixin4j/mp/api/DataApi.java | 133 +++++++++++++ .../mp/datacube/ArticleDatacube1.java | 100 ++++++++++ .../mp/datacube/ArticleDatacube2.java | 37 ++++ .../mp/datacube/ArticleDatacubeShare.java | 84 +++++++++ .../weixin4j/mp/datacube/ArticleSummary.java | 65 +++++++ .../weixin4j/mp/datacube/ArticleTotal.java | 67 +++++++ .../mp/datacube/InterfaceSummary.java | 89 +++++++++ .../weixin4j/mp/datacube/UpstreamMsg.java | 92 +++++++++ .../weixin4j/mp/datacube/UpstreamMsgDist.java | 59 ++++++ .../weixin4j/mp/datacube/UserSummary.java | 91 +++++++++ .../weixin4j/mp/type/DatacubeType.java | 110 +++++++++++ .../weixin4j/mp/type/ShareSourceType.java | 17 ++ .../weixin4j/mp/type/UserSourceType.java | 24 +++ .../foxinmy/weixin4j/mp/test/DataApiTest.java | 104 +++++++++++ .../com/foxinmy/weixin4j/mp/test/PayTest.java | 175 ++++++++++++++++++ 15 files changed, 1247 insertions(+) create mode 100644 weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/DataApi.java create mode 100644 weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleDatacube1.java create mode 100644 weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleDatacube2.java create mode 100644 weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleDatacubeShare.java create mode 100644 weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleSummary.java create mode 100644 weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleTotal.java create mode 100644 weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/InterfaceSummary.java create mode 100644 weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/UpstreamMsg.java create mode 100644 weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/UpstreamMsgDist.java create mode 100644 weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/UserSummary.java create mode 100644 weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/DatacubeType.java create mode 100644 weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/ShareSourceType.java create mode 100644 weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/UserSourceType.java create mode 100644 weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/DataApiTest.java create mode 100644 weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/DataApi.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/DataApi.java new file mode 100644 index 00000000..73ede162 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/DataApi.java @@ -0,0 +1,133 @@ +package com.foxinmy.weixin4j.mp.api; + +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.Response; +import com.foxinmy.weixin4j.model.Token; +import com.foxinmy.weixin4j.mp.type.DatacubeType; +import com.foxinmy.weixin4j.token.TokenHolder; +import com.foxinmy.weixin4j.util.DateUtil; + +/** + * 数据分析API + *

+ * 1、接口侧的公众号数据的数据库中仅存储了2014年12月1日之后的数据,将查询不到在此之前的日期,即使有查到,也是不可信的脏数据; + * 2、请开发者在调用接口获取数据后,将数据保存在自身数据库中,即加快下次用户的访问速度,也降低了微信侧接口调用的不必要损耗。 + *

+ * + * @className DataApi + * @author jy + * @date 2015年1月7日 + * @since JDK 1.7 + * @see + */ +public class DataApi extends MpApi { + private final TokenHolder tokenHolder; + + public DataApi(TokenHolder tokenHolder) { + this.tokenHolder = tokenHolder; + } + + /** + * 数据统计 + * + * @param datacubeType + * 统计类型 + * @param beginDate + * 开始日期 + * @param offset + * 增量 表示向前几天 比如 offset=1 则查询 beginDate的后一天之间的数据 + * @return + * @throws WeixinException + */ + public List datacube(DatacubeType datacubeType, Date beginDate, + int offset) throws WeixinException { + Calendar ca = Calendar.getInstance(); + ca.setTime(beginDate); + ca.add(Calendar.DAY_OF_MONTH, offset); + return datacube(datacubeType, beginDate, ca.getTime()); + } + + /** + * 数据统计 + * + * @param datacubeType + * 统计类型 + * @param offset + * 增量 表示向后几天 比如 offset=1 则查询 beginDate的前一天之间的数据 + * @param endDate + * 截至日期 + * @return + * @throws WeixinException + */ + public List datacube(DatacubeType datacubeType, int offset, Date endDate) + throws WeixinException { + Calendar ca = Calendar.getInstance(); + ca.setTime(endDate); + ca.add(Calendar.DAY_OF_MONTH, 0 - offset); + return datacube(datacubeType, ca.getTime(), endDate); + } + + /** + * 查询日期跨度为1的统计数据 + * + * @param datacubeType + * 统计类型 + * @param date + * 统计日期 + * @return 统计结果 + * @throws WeixinException + */ + public List datacube(DatacubeType datacubeType, Date date) + throws WeixinException { + return datacube(datacubeType, date, date); + } + + /** + * 数据统计 + * + * @param datacubeType + * 数据统计类型 + * @param beginDate + * 获取数据的起始日期,begin_date和end_date的差值需小于“最大时间跨度”(比如最大时间跨度为1时, + * begin_date和end_date的差值只能为0,才能小于1),否则会报错 + * @param endDate + * 获取数据的结束日期,end_date允许设置的最大值为昨日 + * @see com.foxinmy.weixin4j.mp.datacube.UserSummary + * @see com.foxinmy.weixin4j.mp.datacube.ArticleSummary + * @see com.foxinmy.weixin4j.mp.datacube.ArticleTotal + * @see com.foxinmy.weixin4j.mp.datacube.ArticleDatacubeShare + * @see com.foxinmy.weixin4j.mp.datacube.UpstreamMsg + * @see com.foxinmy.weixin4j.mp.datacube.UpstreamMsgDist + * @see com.foxinmy.weixin4j.mp.datacube.InterfaceSummary + * @return 统计结果 + * @see 用户分析 + * @see 图文分析 + * @see 消息分析 + * @see 接口分析 + * @throws WeixinException + */ + public List datacube(DatacubeType datacubeType, Date beginDate, + Date endDate) throws WeixinException { + String datacube_uri = getRequestUri("datacube_uri"); + Token token = tokenHolder.getToken(); + JSONObject obj = new JSONObject(); + obj.put("begin_date", DateUtil.fortmat2yyyy_MM_dd(beginDate)); + obj.put("end_date", DateUtil.fortmat2yyyy_MM_dd(endDate)); + Response response = request.post(String.format(datacube_uri, + datacubeType.name().toLowerCase(), token.getAccessToken()), obj + .toJSONString()); + + return JSON.parseArray(response.getAsJson().getString("list"), + datacubeType.getClazz()); + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleDatacube1.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleDatacube1.java new file mode 100644 index 00000000..5970b579 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleDatacube1.java @@ -0,0 +1,100 @@ +package com.foxinmy.weixin4j.mp.datacube; + +import java.io.Serializable; + +import com.alibaba.fastjson.annotation.JSONField; + +public class ArticleDatacube1 implements Serializable { + + private static final long serialVersionUID = 4140706754295502971L; + + @JSONField(name = "int_page_read_user") + private int intPageReadUser;// 图文页(点击群发图文卡片进入的页面)的阅读人数 + @JSONField(name = "int_page_read_count") + private int intPageReadCount;// 图文页的阅读次数 + @JSONField(name = "ori_page_read_user") + private int oriPageReadUser;// 原文页(点击图文页“阅读原文”进入的页面)的阅读人数,无原文页时此处数据为0 + @JSONField(name = "ori_page_read_count") + private int oriPageReadCount;// 原文页的阅读次数 + @JSONField(name = "shareUser") + private int shareUser; // 分享的人数 + @JSONField(name = "shareCount") + private int shareCount;// 分享的次数 + @JSONField(name = "add_to_fav_user") + private int favUser;// 收藏的人数 + @JSONField(name = "add_to_fav_count") + private int favCount;// 收藏的次数 + + public int getIntPageReadUser() { + return intPageReadUser; + } + + public void setIntPageReadUser(int intPageReadUser) { + this.intPageReadUser = intPageReadUser; + } + + public int getIntPageReadCount() { + return intPageReadCount; + } + + public void setIntPageReadCount(int intPageReadCount) { + this.intPageReadCount = intPageReadCount; + } + + public int getOriPageReadUser() { + return oriPageReadUser; + } + + public void setOriPageReadUser(int oriPageReadUser) { + this.oriPageReadUser = oriPageReadUser; + } + + public int getOriPageReadCount() { + return oriPageReadCount; + } + + public void setOriPageReadCount(int oriPageReadCount) { + this.oriPageReadCount = oriPageReadCount; + } + + public int getShareUser() { + return shareUser; + } + + public void setShareUser(int shareUser) { + this.shareUser = shareUser; + } + + public int getShareCount() { + return shareCount; + } + + public void setShareCount(int shareCount) { + this.shareCount = shareCount; + } + + public int getFavUser() { + return favUser; + } + + public void setFavUser(int favUser) { + this.favUser = favUser; + } + + public int getFavCount() { + return favCount; + } + + public void setFavCount(int favCount) { + this.favCount = favCount; + } + + @Override + public String toString() { + return " intPageReadUser=" + intPageReadUser + ", intPageReadCount=" + + intPageReadCount + ", oriPageReadUser=" + oriPageReadUser + + ", oriPageReadCount=" + oriPageReadCount + ", share_user=" + + shareUser + ", share_count=" + shareCount + ", favUser=" + + favUser + ", favCount=" + favCount; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleDatacube2.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleDatacube2.java new file mode 100644 index 00000000..1571b7a2 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleDatacube2.java @@ -0,0 +1,37 @@ +package com.foxinmy.weixin4j.mp.datacube; + +import java.util.Date; + +import com.alibaba.fastjson.annotation.JSONField; + +public class ArticleDatacube2 extends ArticleDatacube1 { + private static final long serialVersionUID = -2924534868674264316L; + + @JSONField(name = "stat_date") + private Date statDate; + @JSONField(name = "target_user") + private int targetUser; + + public Date getStatDate() { + return statDate; + } + + public void setStatDate(Date statDate) { + this.statDate = statDate; + } + + public int getTargetUser() { + return targetUser; + } + + public void setTargetUser(int targetUser) { + this.targetUser = targetUser; + } + + @Override + public String toString() { + return "statDate=" + statDate + ", targetUser=" + targetUser + ", " + + super.toString(); + } + +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleDatacubeShare.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleDatacubeShare.java new file mode 100644 index 00000000..01ea2533 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleDatacubeShare.java @@ -0,0 +1,84 @@ +package com.foxinmy.weixin4j.mp.datacube; + +import java.io.Serializable; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.mp.type.ShareSourceType; + +/** + * 数据统计:图文分享数据 + * @className ArticleDatacubeShare + * @author jy + * @date 2015年1月30日 + * @since JDK 1.7 + * @see + */ +public class ArticleDatacubeShare implements Serializable { + private static final long serialVersionUID = 3841239305410294553L; + + @JSONField(name = "ref_date") + private String refDate; // 数据的日期 + @JSONField(name = "ref_hour") + private int refHour; // 数据的小时,包括从000到2300,分别代表的是[000,100)到[2300,2400),即每日的第1小时和最后1小时 + @JSONField(name = "shareUser") + private int shareUser; // 分享的人数 + @JSONField(name = "shareCount") + private int shareCount;// 分享的次数 + @JSONField(name = "share_scene") + private int shareScene;// 分享的场景 + + public String getRefDate() { + return refDate; + } + + public void setRefDate(String refDate) { + this.refDate = refDate; + } + + public int getRefHour() { + return refHour; + } + + public void setRefHour(int refHour) { + this.refHour = refHour; + } + + public int getShareUser() { + return shareUser; + } + + public void setShareUser(int shareUser) { + this.shareUser = shareUser; + } + + public int getShareCount() { + return shareCount; + } + + public void setShareCount(int shareCount) { + this.shareCount = shareCount; + } + + public ShareSourceType getShareScene() { + if (shareScene == 1) { + return ShareSourceType.FRIENDFORWARD; + } else if (shareScene == 2) { + return ShareSourceType.FRIENDSCIRCLE; + } else if (shareScene == 3) { + return ShareSourceType.TENCENTWEIBO; + } else { + return ShareSourceType.OTHER; + } + } + + public void setShareScene(int shareScene) { + this.shareScene = shareScene; + } + + @Override + public String toString() { + return "ArticleDatacubeShare [refDate=" + refDate + ", refHour=" + + refHour + ", shareUser=" + shareUser + ", shareCount=" + + shareCount + ", shareScene=" + shareScene + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleSummary.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleSummary.java new file mode 100644 index 00000000..cc2f2155 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleSummary.java @@ -0,0 +1,65 @@ +package com.foxinmy.weixin4j.mp.datacube; + +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 数据统计:图文群发每日数据 + * + * @className ArticleSummary + * @author jy + * @date 2015年1月30日 + * @since JDK 1.7 + * @see + */ +public class ArticleSummary extends ArticleDatacube1 { + private static final long serialVersionUID = 4820605570501368550L; + @JSONField(name = "ref_date") + private String refDate; // 数据的日期 + @JSONField(name = "ref_hour") + private int refHour; // 数据的小时,包括从000到2300,分别代表的是[000,100)到[2300,2400),即每日的第1小时和最后1小时 + /** + * 这里的msgid实际上是由msgid(图文消息id)和index(消息次序索引)组成, 例如12003_3, + * 其中12003是msgid,即一次群发的id消息的; 3为index,假设该次群发的图文消息共5个文章(因为可能为多图文), 3表示5个中的第3个 + */ + private String msgid; + private String title;// 图文消息的标题 + + public String getRefDate() { + return refDate; + } + + public void setRefDate(String refDate) { + this.refDate = refDate; + } + + public int getRefHour() { + return refHour; + } + + public void setRefHour(int refHour) { + this.refHour = refHour; + } + + public String getMsgid() { + return msgid; + } + + public void setMsgid(String msgid) { + this.msgid = msgid; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + @Override + public String toString() { + return "ArticleSummary [refDate=" + refDate + ", refHour=" + refHour + + ", msgid=" + msgid + ", title=" + title + ", " + + super.toString() + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleTotal.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleTotal.java new file mode 100644 index 00000000..24da3b36 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/ArticleTotal.java @@ -0,0 +1,67 @@ +package com.foxinmy.weixin4j.mp.datacube; + +import java.io.Serializable; +import java.util.List; + +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 数据统计:图文群发总数据 + * + * @className ArticleTotal + * @author jy + * @date 2015年1月30日 + * @since JDK 1.7 + * @see + */ +public class ArticleTotal implements Serializable { + private static final long serialVersionUID = -6820948857241500950L; + + @JSONField(name = "ref_date") + private String refDate; // 数据的日期 + /** + * 这里的msgid实际上是由msgid(图文消息id)和index(消息次序索引)组成, 例如12003_3, + * 其中12003是msgid,即一次群发的id消息的; 3为index,假设该次群发的图文消息共5个文章(因为可能为多图文), 3表示5个中的第3个 + */ + private String msgid; + private String title;// 图文消息的标题 + private List details; + + public String getRefDate() { + return refDate; + } + + public void setRefDate(String refDate) { + this.refDate = refDate; + } + + public String getMsgid() { + return msgid; + } + + public void setMsgid(String msgid) { + this.msgid = msgid; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public List getDetails() { + return details; + } + + public void setDetails(List details) { + this.details = details; + } + + @Override + public String toString() { + return "ArticleTotal [refDate=" + refDate + ", msgid=" + msgid + + ", title=" + title + ", details=" + details + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/InterfaceSummary.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/InterfaceSummary.java new file mode 100644 index 00000000..2272f071 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/InterfaceSummary.java @@ -0,0 +1,89 @@ +package com.foxinmy.weixin4j.mp.datacube; + +import java.io.Serializable; +import java.util.Date; + +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 数据统计:接口分析数据 + * + * @className InterfaceSummary + * @author jy + * @date 2015年1月30日 + * @since JDK 1.7 + * @see + */ +public class InterfaceSummary implements Serializable { + + private static final long serialVersionUID = -8812979112580350988L; + + @JSONField(name = "ref_date") + private Date refDate; // 引用的日期 + @JSONField(name = "ref_hour") + private int refHour; // 数据的小时,包括从000到2300,分别代表的是[000,100)到[2300,2400),即每日的第1小时和最后1小时 + @JSONField(name = "callback_count") + private int callbackCount; // 通过服务器配置地址获得消息后,被动回复用户消息的次数 + @JSONField(name = "fail_count") + private int failCount; // 上述动作的失败次数 + @JSONField(name = "total_time_cost") + private int totalTimeCost;// 总耗时,除以callback_count即为平均耗时 + @JSONField(name = "max_time_cost") + private int maxTimeCost;// 最大耗时 + + public Date getRefDate() { + return refDate; + } + + public void setRefDate(Date refDate) { + this.refDate = refDate; + } + + public int getRefHour() { + return refHour; + } + + public void setRefHour(int refHour) { + this.refHour = refHour; + } + + public int getCallbackCount() { + return callbackCount; + } + + public void setCallbackCount(int callbackCount) { + this.callbackCount = callbackCount; + } + + public int getFailCount() { + return failCount; + } + + public void setFailCount(int failCount) { + this.failCount = failCount; + } + + public int getTotalTimeCost() { + return totalTimeCost; + } + + public void setTotalTimeCost(int totalTimeCost) { + this.totalTimeCost = totalTimeCost; + } + + public int getMaxTimeCost() { + return maxTimeCost; + } + + public void setMaxTimeCost(int maxTimeCost) { + this.maxTimeCost = maxTimeCost; + } + + @Override + public String toString() { + return "InterfaceSummary [refDate=" + refDate + ", refHour=" + refHour + + ", callbackCount=" + callbackCount + ", failCount=" + + failCount + ", totalTimeCost=" + totalTimeCost + + ", maxTimeCost=" + maxTimeCost + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/UpstreamMsg.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/UpstreamMsg.java new file mode 100644 index 00000000..44f46817 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/UpstreamMsg.java @@ -0,0 +1,92 @@ +package com.foxinmy.weixin4j.mp.datacube; + +import java.io.Serializable; +import java.util.Date; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.type.MessageType; + +/** + * 数据统计:消息发送概况数据 + * + * @className UpstreamMsg + * @author jy + * @date 2015年1月30日 + * @since JDK 1.7 + * @see + */ +public class UpstreamMsg implements Serializable { + + private static final long serialVersionUID = -2605207523094962029L; + @JSONField(name = "ref_date") + private Date refDate; // 引用的日期 + @JSONField(name = "ref_hour") + private int refHour; // 数据的小时,包括从000到2300,分别代表的是[000,100)到[2300,2400),即每日的第1小时和最后1小时 + @JSONField(name = "msg_type") + private int msgType; // 消息类型 + @JSONField(name = "msg_user") + private int msgUser; // 上行发送了(向公众号发送了)消息的用户数 + @JSONField(name = "msg_count") + private int msgCount;// 上行发送了消息的消息总数 + + public Date getRefDate() { + return refDate; + } + + public void setRefDate(Date refDate) { + this.refDate = refDate; + } + + public int getRefHour() { + return refHour; + } + + public void setRefHour(int refHour) { + this.refHour = refHour; + } + + public MessageType getMsgType() { + // 1代表文字 2代表图片 3代表语音 4代表视频 6代表第三方应用消息(链接消息) + switch (msgType) { + case 1: + return MessageType.text; + case 2: + return MessageType.image; + case 3: + return MessageType.voice; + case 4: + return MessageType.video; + case 6: + return MessageType.link; + default: + return null; + } + } + + public void setMsgType(int msgType) { + this.msgType = msgType; + } + + public int getMsgUser() { + return msgUser; + } + + public void setMsgUser(int msgUser) { + this.msgUser = msgUser; + } + + public int getMsgCount() { + return msgCount; + } + + public void setMsgCount(int msgCount) { + this.msgCount = msgCount; + } + + @Override + public String toString() { + return "UpstreamMsg [refDate=" + refDate + ", refHour=" + refHour + + ", msgType=" + msgType + ", msgUser=" + msgUser + + ", msgCount=" + msgCount + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/UpstreamMsgDist.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/UpstreamMsgDist.java new file mode 100644 index 00000000..1dbd47f0 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/UpstreamMsgDist.java @@ -0,0 +1,59 @@ +package com.foxinmy.weixin4j.mp.datacube; + +import java.io.Serializable; +import java.util.Date; + +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 数据统计:消息发送分布数据 + * + * @className UpstreamMsgDist + * @author jy + * @date 2015年1月30日 + * @since JDK 1.7 + * @see + */ +public class UpstreamMsgDist implements Serializable { + + private static final long serialVersionUID = -2605207523094962029L; + @JSONField(name = "ref_date") + private Date refDate; // 引用的日期 + @JSONField(name = "msg_user") + private int msgUser; // 上行发送了(向公众号发送了)消息的用户数 + /** + * 当日发送消息量分布的区间,0代表 “0”,1代表“1-5”,2代表“6-10”,3代表“10次以上 + */ + @JSONField(name = "count_interval") + private int countInterval; + + public Date getRefDate() { + return refDate; + } + + public void setRefDate(Date refDate) { + this.refDate = refDate; + } + + public int getMsgUser() { + return msgUser; + } + + public void setMsgUser(int msgUser) { + this.msgUser = msgUser; + } + + public int getCountInterval() { + return countInterval; + } + + public void setCountInterval(int countInterval) { + this.countInterval = countInterval; + } + + @Override + public String toString() { + return "UpstreamMsgDist [refDate=" + refDate + ", msgUser=" + msgUser + + ", countInterval=" + countInterval + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/UserSummary.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/UserSummary.java new file mode 100644 index 00000000..74895043 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/datacube/UserSummary.java @@ -0,0 +1,91 @@ +package com.foxinmy.weixin4j.mp.datacube; + +import java.io.Serializable; +import java.util.Date; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.mp.type.UserSourceType; + +/** + * 数据统计:用户增减 + * + * @className UserSummary + * @author jy + * @date 2015年1月25日 + * @since JDK 1.7 + * @see + */ +public class UserSummary implements Serializable { + + private static final long serialVersionUID = 5303181828798568052L; + @JSONField(name = "ref_date") + private Date refDate; // 数据的日期 + @JSONField(name = "user_source") + private int userSource; // 用户的渠道,数值代表的含义如下:0代表其他 30代表扫二维码 17代表名片分享 + // 35代表搜号码(即微信添加朋友页的搜索) 39代表查询微信公众帐号 43代表图文页右上角菜单 + @JSONField(name = "new_user") + private int newUser; // 新增的用户数量 + @JSONField(name = "cancel_user") + private int cancelUser; // 取消关注的用户数量,new_user减去cancel_user即为净增用户数量 + @JSONField(name = "cumulate_user") + private int cumulateUser; // 总用户量 + + public Date getRefDate() { + return refDate; + } + + public void setRefDate(Date refDate) { + this.refDate = refDate; + } + + public UserSourceType getUserSource() { + if (userSource == 30) { + return UserSourceType.QRCODE; + } else if (userSource == 17) { + return UserSourceType.CARDSHARE; + } else if (userSource == 35) { + return UserSourceType.SONUMBER; + } else if (userSource == 39) { + return UserSourceType.SOMPACCOUNT; + } else if (userSource == 43) { + return UserSourceType.ARTICLEMENU; + } else { + return UserSourceType.OTHER; + } + } + + public void setUserSource(int userSource) { + this.userSource = userSource; + } + + public int getNewUser() { + return newUser; + } + + public void setNewUser(int newUser) { + this.newUser = newUser; + } + + public int getCancelUser() { + return cancelUser; + } + + public void setCancelUser(int cancelUser) { + this.cancelUser = cancelUser; + } + + public int getCumulateUser() { + return cumulateUser; + } + + public void setCumulateUser(int cumulateUser) { + this.cumulateUser = cumulateUser; + } + + @Override + public String toString() { + return "UserSummary [refDate=" + refDate + ", userSource=" + + getUserSource() + ", newUser=" + newUser + ", cancelUser=" + + cancelUser + ", cumulateUser=" + cumulateUser + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/DatacubeType.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/DatacubeType.java new file mode 100644 index 00000000..e5be72a3 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/DatacubeType.java @@ -0,0 +1,110 @@ +package com.foxinmy.weixin4j.mp.type; + +import com.foxinmy.weixin4j.mp.datacube.ArticleDatacubeShare; +import com.foxinmy.weixin4j.mp.datacube.ArticleSummary; +import com.foxinmy.weixin4j.mp.datacube.ArticleTotal; +import com.foxinmy.weixin4j.mp.datacube.InterfaceSummary; +import com.foxinmy.weixin4j.mp.datacube.UpstreamMsg; +import com.foxinmy.weixin4j.mp.datacube.UpstreamMsgDist; +import com.foxinmy.weixin4j.mp.datacube.UserSummary; + +/** + * 数据统计类型 + * + * @className DatacubeType + * @author jy + * @date 2015年1月25日 + * @since JDK 1.7 + * @see + */ +public enum DatacubeType { + /** + * 获取用户增减数据 + */ + GETUSERSUMMARY(UserSummary.class), + /** + * 获取累计用户数据 + */ + GETUSERCUMULATE(UserSummary.class), + /** + * 获取图文群发每日数据 + */ + GETARTICLESUMMARY(ArticleSummary.class), + /** + * 获取图文群发总数据,获取的是某天所有被阅读过的文章(仅包括群发的文章)在当天的阅读次数等数据。 + */ + GETARTICLETOTAL(ArticleTotal.class), + /** + * 获取图文统计数据,获取的是某天群发的文章,从群发日起到接口调用日(但最多统计发表日后7天数据), + * 每天的到当天的总等数据。例如某篇文章是12月1日发出的,发出后在1日 + * 、2日、3日的阅读次数分别为1万,则getarticletotal获取到的数据为 + * ,距发出到12月1日24时的总阅读量为1万,距发出到12月2日24时的总阅读量为2万,距发出到12月1日24时的总阅读量为3万。 + */ + GETUSERREAD(ArticleSummary.class), + /** + * 获取图文统计分时数据 + */ + GETUSERREADHOUR(ArticleSummary.class), + /** + * 获取图文分享转发数据 + */ + GETUSERSHARE(ArticleDatacubeShare.class), + /** + * 获取图文分享转发分时数据 + */ + GETUSERSHAREHOUR(ArticleDatacubeShare.class), + + /** + * 获取消息发送概况数据 + */ + GETUPSTREAMMSG(UpstreamMsg.class), + /** + * 获取消息分送分时数据 + */ + GETUPSTREAMMSGHOUR(UpstreamMsg.class), + /** + * 获取消息发送周数据 + * 关于周数据与月数据,请注意:每个月/周的周期数据的数据标注日期在当月/当周的第一天(当月1日或周一)。在某一月/周过后去调用接口 + * ,才能获取到该周期的数据 + * 。比如,在12月1日以(11月1日-11月5日)作为(begin_date和end_date)调用获取月数据接口,可以获取到11月1日的月数据 + * (即11月的月数据)。 + */ + GETUPSTREAMMSGWEEK(UpstreamMsg.class), + /** + * 获取消息发送月数据 + */ + GETUPSTREAMMSGMONTH(UpstreamMsg.class), + + /** + * 获取消息发送分布数据 + */ + GETUPSTREAMMSGDIST(UpstreamMsgDist.class), + + /** + * 获取消息发送分布周数据 + */ + GETUPSTREAMMSGDISTWEEK(UpstreamMsgDist.class), + + /** + * 获取消息发送分布月数据 + */ + GETUPSTREAMMSGDISTMONTH(UpstreamMsgDist.class), + /** + * 获取接口分析数据 + */ + GETINTERFACESUMMARY(InterfaceSummary.class), + /** + * 获取接口分析分时数据 + */ + GETINTERFACESUMMARYHOUR(InterfaceSummary.class); + + private Class clazz; + + DatacubeType(Class clazz) { + this.clazz = clazz; + } + + public Class getClazz() { + return clazz; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/ShareSourceType.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/ShareSourceType.java new file mode 100644 index 00000000..e324385b --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/ShareSourceType.java @@ -0,0 +1,17 @@ +package com.foxinmy.weixin4j.mp.type; + +/** + * 分享的场景 + * + * @className ShareSourceType + * @author jy + * @date 2015年1月30日 + * @since JDK 1.7 + * @see + */ +public enum ShareSourceType { + FRIENDFORWARD, // 好友转发 + FRIENDSCIRCLE, // 朋友圈 + TENCENTWEIBO, // 腾讯微博 + OTHER // 其它 +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/UserSourceType.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/UserSourceType.java new file mode 100644 index 00000000..eabc0103 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/UserSourceType.java @@ -0,0 +1,24 @@ +package com.foxinmy.weixin4j.mp.type; + +/** + * 用户渠道来源 + * + * @className UserSourceType + * @author jy + * @date 2015年1月25日 + * @since JDK 1.7 + * @see + */ +public enum UserSourceType { + OTHER("其它"), QRCODE("扫二维码"), CARDSHARE("名片分享"), SONUMBER("搜号码(即微信添加朋友页的搜索)"), SOMPACCOUNT( + "查询微信公众帐号"), ARTICLEMENU("图文页右上角菜单"); + private String desc; + + UserSourceType(String desc) { + this.desc = desc; + } + + public String getDesc() { + return desc; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/DataApiTest.java b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/DataApiTest.java new file mode 100644 index 00000000..7db1f8f8 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/DataApiTest.java @@ -0,0 +1,104 @@ +package com.foxinmy.weixin4j.mp.test; + +import java.util.Calendar; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.mp.api.DataApi; +import com.foxinmy.weixin4j.mp.datacube.ArticleDatacubeShare; +import com.foxinmy.weixin4j.mp.datacube.ArticleSummary; +import com.foxinmy.weixin4j.mp.datacube.ArticleTotal; +import com.foxinmy.weixin4j.mp.type.DatacubeType; + +/** + * 数据分析测试 + * + * @className DataApiTest + * @author jy + * @date 2015年1月25日 + * @since JDK 1.7 + * @see + */ +@SuppressWarnings("unchecked") +public class DataApiTest extends TokenTest { + private DataApi dataApi; + + @Before + public void init() { + dataApi = new DataApi(tokenHolder); + } + + @Test + public void testUserCumulate() throws WeixinException { + Calendar ca = Calendar.getInstance(); + ca.add(Calendar.DAY_OF_MONTH, -7); + List userSummaryList = dataApi.datacube( + DatacubeType.GETUSERCUMULATE, ca.getTime(), 3); + System.err.println(userSummaryList); + } + + @Test + public void testUserSummary() throws WeixinException { + Calendar ca = Calendar.getInstance(); + ca.add(Calendar.DAY_OF_MONTH, -7); + List userSummaryList = dataApi.datacube(DatacubeType.GETUSERSUMMARY, + ca.getTime(), 3); + System.err.println(userSummaryList); + } + + @Test + public void testArticleSummary() throws WeixinException { + Calendar ca = Calendar.getInstance(); + ca.add(Calendar.DAY_OF_MONTH, -7); + List articleSummaryList = (List) dataApi + .datacube(DatacubeType.GETARTICLESUMMARY, ca.getTime()); + System.err.println(articleSummaryList); + } + + @Test + public void testArticleTotal() throws WeixinException { + Calendar ca = Calendar.getInstance(); + ca.add(Calendar.DAY_OF_MONTH, -7); + List articleTotalList = (List) dataApi + .datacube(DatacubeType.GETARTICLETOTAL, ca.getTime()); + System.err.println(articleTotalList); + } + + @Test + public void testUserReadHour() throws WeixinException { + Calendar ca = Calendar.getInstance(); + ca.add(Calendar.DAY_OF_MONTH, -7); + List articleSummaryList = (List) dataApi + .datacube(DatacubeType.GETUSERREADHOUR, ca.getTime()); + System.err.println(articleSummaryList); + } + + @Test + public void testUserShare() throws WeixinException { + Calendar ca = Calendar.getInstance(); + ca.add(Calendar.DAY_OF_MONTH, -7); + List userShareList = (List) dataApi + .datacube(DatacubeType.GETUSERSHAREHOUR, ca.getTime()); + System.err.println(userShareList); + } + + @Test + public void testDatecube() throws WeixinException { + Calendar ca = Calendar.getInstance(); + ca.add(Calendar.DAY_OF_MONTH, -1); + List datacuteList = dataApi.datacube(DatacubeType.GETUPSTREAMMSG, + ca.getTime()); + System.err.println(datacuteList); + //dataApi.datacube(DatacubeType.GETUPSTREAMMSGMONTH, ca.getTime()); + System.err.println(datacuteList); + + //dataApi.datacube(DatacubeType.GETUPSTREAMMSGDISTMONTH, ca.getTime()); + System.err.println(datacuteList); + + dataApi.datacube(DatacubeType.GETINTERFACESUMMARYHOUR, ca.getTime()); + System.err.println(datacuteList); + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java new file mode 100644 index 00000000..d5818d4c --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java @@ -0,0 +1,175 @@ +package com.foxinmy.weixin4j.mp.test; + +import java.io.File; +import java.util.Calendar; +import java.util.Date; + +import org.junit.Assert; +import org.junit.Test; + +import com.foxinmy.weixin4j.exception.PayException; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.XmlResult; +import com.foxinmy.weixin4j.model.WeixinMpAccount; +import com.foxinmy.weixin4j.mp.WeixinPayProxy; +import com.foxinmy.weixin4j.mp.payment.PayUtil; +import com.foxinmy.weixin4j.mp.payment.v3.ApiResult; +import com.foxinmy.weixin4j.mp.payment.v3.Order; +import com.foxinmy.weixin4j.mp.payment.v3.PayPackageV3; +import com.foxinmy.weixin4j.mp.payment.v3.PrePay; +import com.foxinmy.weixin4j.mp.type.IdQuery; +import com.foxinmy.weixin4j.mp.type.IdType; +import com.foxinmy.weixin4j.mp.type.TradeType; +import com.foxinmy.weixin4j.token.FileTokenHolder; +import com.foxinmy.weixin4j.token.WeixinTokenCreator; +import com.foxinmy.weixin4j.type.AccountType; + +public class PayTest { + private final static WeixinPayProxy PAY2; + private final static WeixinPayProxy PAY3; + private final static WeixinMpAccount ACCOUNT2; + private final static WeixinMpAccount ACCOUNT3; + static { + ACCOUNT2 = new WeixinMpAccount( + "appId", + "appSecret", + "paySignKey", + "partnerId", "partnerKey"); + PAY2 = new WeixinPayProxy(ACCOUNT2, new FileTokenHolder( + new WeixinTokenCreator(ACCOUNT2.getId(), ACCOUNT2.getSecret(), + AccountType.MP))); + ACCOUNT3 = new WeixinMpAccount("appId", + "appSecret", + "paySignKey", "mchId"); + PAY3 = new WeixinPayProxy(ACCOUNT3, new FileTokenHolder( + new WeixinTokenCreator(ACCOUNT3.getId(), ACCOUNT3.getSecret(), + AccountType.MP))); + } + + @Test + public void orderQueryV2() throws WeixinException { + System.err.println(PAY2.orderQueryV2("D14110500021")); + } + + @Test + public void refundV2() throws WeixinException { + File caFile = new File( + "/Users/jy/download/1221928801.pfx"); + IdQuery idQuery = new IdQuery("D15012400026", IdType.TRADENO); + System.err.println(PAY2.refundV2(caFile, idQuery, "R000000001", 2d, 2d, + "1221928801", "111111", null, null, null)); + } + + @Test + public void refundQueryV2() throws WeixinException { + System.err.println(PAY2.refundQueryV2(new IdQuery("D14123000004", + IdType.TRADENO))); + refundQueryV3(); + } + + @Test + public void downbillV2() throws WeixinException { + Calendar c = Calendar.getInstance(); + c.set(Calendar.YEAR, 2014); + c.set(Calendar.MONTH, 11); + c.set(Calendar.DAY_OF_MONTH, 22); + File file = PAY2.downloadbill(c.getTime(), null); + System.err.println(file); + } + + @Test + public void orderQueryV3() throws WeixinException { + Order order = PAY3.orderQueryV3(new IdQuery("T0002", IdType.TRADENO)); + System.err.println(order); + String sign = order.getSign(); + order.setSign(null); + String valiSign = PayUtil.paysignMd5(order, ACCOUNT3.getPaySignKey()); + System.err + .println(String.format("sign=%s,valiSign=%s", sign, valiSign)); + Assert.assertEquals(valiSign, sign); + } + + @Test + public void refundQueryV3() throws WeixinException { + System.err.println(PAY3.refundQueryV3(new IdQuery("T00015", + IdType.TRADENO))); + } + + @Test + public void downbillV3() throws WeixinException { + Calendar c = Calendar.getInstance(); + System.err.println(c.getTime()); + c.set(Calendar.YEAR, 2014); + c.set(Calendar.MONTH, 9); + c.set(Calendar.DAY_OF_MONTH, 22); + System.err.println(c.getTime()); + File file = PAY3.downloadbill(c.getTime(), null); + System.err.println(file); + } + + @Test + public void refundV3() throws WeixinException { + File caFile = new File( + "/Users/jy/download/10020674.p12"); + IdQuery idQuery = new IdQuery("T00015", IdType.TRADENO); + com.foxinmy.weixin4j.mp.payment.v3.RefundResult result = PAY3.refundV3( + caFile, idQuery, "R0002", 1d, 1d, "10020674"); + System.err.println(result); + String sign = result.getSign(); + result.setSign(null); + String valiSign = PayUtil.paysignMd5(result, ACCOUNT3.getPaySignKey()); + System.err + .println(String.format("sign=%s,valiSign=%s", sign, valiSign)); + Assert.assertEquals(valiSign, sign); + } + + @Test + public void nativeV3() throws WeixinException { + PayPackageV3 payPackageV3 = new PayPackageV3(ACCOUNT3, + "oyFLst1bqtuTcxK-ojF8hOGtLQao", "native测试", "T0001", 0.1d, + "127.0.0.1", TradeType.NATIVE); + payPackageV3.setProductId("0001"); + payPackageV3.setNotifyUrl("xxxx"); + PrePay prePay = null; + try { + prePay = PayUtil.createPrePay(payPackageV3, + ACCOUNT3.getPaySignKey()); + } catch (PayException e) { + e.printStackTrace(); + } + System.err.println(prePay); + } + + @Test + public void closeOrder() throws WeixinException { + ApiResult result = PAY3.closeOrder("D111"); + System.err.println(result); + String sign = result.getSign(); + result.setSign(null); + String valiSign = PayUtil.paysignMd5(result, ACCOUNT3.getPaySignKey()); + System.err + .println(String.format("sign=%s,valiSign=%s", sign, valiSign)); + Assert.assertEquals(valiSign, sign); + } + + @Test + public void shortUrl() throws WeixinException { + String url = "weixin://wxpay/bizpayurl?xxxxxx"; + String shortUrl = PAY3.getPayShorturl(url); + System.err.println(shortUrl); + } + + @Test + public void interfaceReport() throws WeixinException { + String interfaceUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder"; + int executeTime = 2500; + String outTradeNo = null; + String ip = "127.0.0.1"; + Date time = new Date(); + XmlResult returnXml = new XmlResult("SUCCESS", ""); + returnXml.setResultCode("SUCCESS"); + returnXml = PAY3.interfaceReport(interfaceUrl, executeTime, outTradeNo, + ip, time, returnXml); + System.err.println(returnXml); + } +}