新增代金券接口&字段上的单行注释调整为文档多行注释

This commit is contained in:
jinyu 2015-03-29 22:45:50 +08:00
parent 5557141b93
commit 464359ae7a
155 changed files with 3825 additions and 591 deletions

View File

@ -204,4 +204,13 @@
+ **weixin4j-qy**: 新增deploy.xml远程部署ant脚本
* 2015-03-29
+ **weixin4j-base**: 单行注释调整为多行文档注释
+ **weixin4j-mp**: 单行注释调整为多行文档注释
+ **weixin4j-mp**: 新增(CouponApi)[./weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/CouponApi.java]代金券接口
+ **weixin4j-qy**: 单行注释调整为多行文档注释

View File

@ -71,12 +71,16 @@ netty的代码没有放到maven中心仓库,也没什么意义,因为最终需
接下来
------
* 代金券 & 红包接口
* 企业号异步接口
* 红包和企业付款接口
* 公众号服务应用
* 企业号第三方应用
* 企业号登陆授权
* 微信小店
* 微信卡券

View File

@ -47,4 +47,8 @@ weixin4j-base
+ 重构token实现机制
+ 新增JSTICKET支持
+ 新增JSTICKET支持
* 2015-03-29
+ 单行注释调整为多行文档注释

View File

@ -196,10 +196,11 @@ public class HttpRequest {
EntityUtils.consume(httpEntity);
Header contentType = httpResponse
.getFirstHeader(HttpHeaders.CONTENT_TYPE);
System.err.println(response.getAsString());
// error with html
if (contentType.getValue().contains(
ContentType.TEXT_HTML.getMimeType())) {
response.setText(new String(data, "gbk"));
// response.setText(new String(data, "gbk"));
try {
checkJson(response);
return response;

View File

@ -16,18 +16,38 @@ public class BaseMsg implements Serializable {
private static final long serialVersionUID = 7761192742840031607L;
/**
* 开发者微信号
*/
@XStreamAlias("ToUserName")
private String toUserName; // 开发者微信号
private String toUserName;
/**
* 发送方账号 即用户的openid
*/
@XStreamAlias("FromUserName")
private String fromUserName; // 发送方帐号一个OpenID
private String fromUserName;
/**
* 消息创建时间 系统毫秒数
*/
@XStreamAlias("CreateTime")
private long createTime = System.currentTimeMillis(); // 消息创建时间 整型
private long createTime = System.currentTimeMillis();
/**
* 消息类型
*
* @see com.foxinmy.weixin4j.type.MessageType
*/
@XStreamAlias("MsgType")
private String msgType; // 消息类型
private String msgType;
/**
* 消息ID 可用于排重
*/
@XStreamAlias("MsgId")
private long msgId; // 消息ID
private long msgId;
@XStreamAlias("AgentID")
private String agentId; // 企业号独有的应用ID
/**
* 企业号独有的应用ID
*/
private String agentId;
public BaseMsg() {

View File

@ -24,17 +24,39 @@ public class Button implements Serializable {
private static final long serialVersionUID = -6422234732203854866L;
/**
* 菜单标题不超过16个字节子菜单不超过40个字节
*/
private String name;
private ButtonType type; // 菜单的响应动作类型
private String key; // click等点击类型必须
private String url; // view类型必须
/**
* 菜单的响应动作类型
*
* @see com.foxinmy.weixin4j.type.ButtonType
*/
private ButtonType type;
/**
* 菜单KEY值用于消息接口推送不超过128字节
*/
private String key;
/**
* view类型必须 网页链接用户点击菜单可打开链接不超过256字节
*/
private String url;
/**
* 二级菜单数组个数应为1~5个
*/
@JSONField(name = "sub_button")
private List<Button> subs;
public Button() {
}
/**
* 创建一个菜单
* @param name 菜单显示的名称
* @param value 当buttonType为view时value设置为url,否则为key.
* @param buttonType 按钮类型
*/
public Button(String name, String value, ButtonType buttonType) {
this.name = name;
this.type = buttonType;

View File

@ -24,13 +24,36 @@ public final class Consts {
public static final String PROTOCOL_FILE = "file";
public static final String PROTOCOL_JAR = "jar";
/**
* oauth验证url
*/
public static final String OAUTH_AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect";
/**
* 公众平台获取token的url
*/
public static final String MP_ASSESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
/**
* 企业号获取token的url
*/
public static final String QY_ASSESS_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s";
/**
* jssdk获取token的url
*/
public static final String JS_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi";
/**
* 商户平台下统一订单生成的url
*/
public static final String UNIFIEDORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
/**
* 商户平台下刷卡支付的url
*/
public static final String MICROPAYURL = "https://api.mch.weixin.qq.com/pay/micropay";
/**
* 商户平台下native支付的url
*/
public static final String NATIVEURLV2 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&productid=%s&timestamp=%s&noncestr=%s";
/**
* V2支付下natvie支付的url
*/
public static final String NATIVEURLV3 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s";
}

View File

@ -10,5 +10,16 @@ package com.foxinmy.weixin4j.model;
* @see
*/
public enum Gender {
male, female, unknown;
/**
*
*/
male,
/**
*
*/
female,
/**
* 未知
*/
unknown;
}

View File

@ -21,10 +21,19 @@ public class Token implements Serializable {
private static final long serialVersionUID = -7564855472419104084L;
/**
* 获取到的凭证
*/
@JSONField(name = "access_token")
private String accessToken;
/**
* 凭证有效时间单位
*/
@JSONField(name = "expires_in")
private int expiresIn;
/**
* token创建的时间 只在FileTokenHolder模式下有效
*/
private long time;
public Token() {

View File

@ -20,14 +20,23 @@ import com.foxinmy.weixin4j.type.AccountType;
public abstract class WeixinAccount implements Serializable {
private static final long serialVersionUID = -6001008896414323534L;
// 唯一的身份标识
/**
* 唯一的身份标识
*/
private String id;
// 调用接口的密钥
/**
* 调用接口的密钥
*/
private String secret;
private String token;
// 安全模式下的加密密钥
/**
* 安全模式下的加密密钥
*/
private String encodingAesKey;
/**
* 账号类型
* @return
*/
public abstract AccountType getAccountType();
public WeixinAccount() {

View File

@ -12,26 +12,44 @@ import com.foxinmy.weixin4j.type.AccountType;
* @author jy
* @date 2014年8月17日
* @since JDK 1.7
* @see<a href=
* "https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=836970804&lang=zh_CN"
* >开发者模式</a>
* @see <a href=
* "https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=836970804&lang=zh_CN"
* >开发者模式</a>
*/
public class WeixinMpAccount extends WeixinAccount {
private static final long serialVersionUID = 3689999353867189585L;
// 支付场景下为用户的openid 其余情况可能是公众号的原始ID
/**
* 支付场景下为用户的openid 其余情况可能是公众号的原始ID
*/
private String openId;
// 公众号支付请求中用于加密的密钥 Key,可验证商户唯一身份,PaySignKey 对应于支付场景中的 appKey
/**
* 公众号支付请求中用于加密的密钥 Key,可验证商户唯一身份,PaySignKey 对应于支付场景中的 appKey
*/
private String paySignKey;
// 财付通商户身份的标识
/**
* 财付通商户身份的标识
*/
private String partnerId;
// 财付通商户权限密钥Key
/**
* 财付通商户权限密钥Key
*/
private String partnerKey;
// 微信支付商户号V3.x版本
/**
* 微信支付分配的商户号(商户平台版)
*/
private String mchId;
// 微信支付分配的设备号
/**
* 微信支付分配的子商户号受理模式下必填(商户平台版)
*/
private String subMchId;
/**
* 微信支付分配的设备号(商户平台版)
*/
private String deviceInfo;
// 微信支付版本号(如果无则按照mchId来做判断)
/**
* 微信支付版本号(如果无则按照mchId来做判断)
*/
private int version;
public String getOpenId() {
@ -93,6 +111,14 @@ public class WeixinMpAccount extends WeixinAccount {
this.version = version;
}
public String getSubMchId() {
return subMchId;
}
public void setSubMchId(String subMchId) {
this.subMchId = subMchId;
}
public WeixinMpAccount() {
}
@ -102,12 +128,12 @@ public class WeixinMpAccount extends WeixinAccount {
}
/**
* V3版本字段
* 商户平台版本(V3)字段
*
* @param appId
* @param appSecret
* @param paySignKey
* @param mchId
* @param appId 公众号唯一的身份ID
* @param appSecret 调用接口的凭证
* @param paySignKey 支付密钥字符串
* @param mchId 微信支付分配的商户号
*/
public WeixinMpAccount(String appId, String appSecret, String paySignKey,
String mchId) {
@ -119,11 +145,11 @@ public class WeixinMpAccount extends WeixinAccount {
/**
* V2版本字段
*
* @param appId
* @param appSecret
* @param paySignKey
* @param partnerId
* @param partnerKey
* @param appId 公众号唯一的身份ID
* @param appSecret 调用接口的凭证
* @param paySignKey 支付密钥字符串
* @param partnerId 财付通账号的ID
* @param partnerKey 财付通账号的key
*/
public WeixinMpAccount(String appId, String appSecret, String paySignKey,
String partnerId, String partnerKey) {

View File

@ -20,6 +20,13 @@ public class WeixinQyAccount extends WeixinAccount {
public WeixinQyAccount() {
}
/**
*
* @param corpid
* 企业ID
* @param corpsecret
* 管理组的凭证密钥
*/
public WeixinQyAccount(String corpid, String corpsecret) {
super(corpid, corpsecret);
}

View File

@ -24,10 +24,16 @@ public class ImageMessage extends BaseMsg {
super(MessageType.image.name());
}
/**
* 图片链接
*/
@XStreamAlias("PicUrl")
private String picUrl; // 图片链接
private String picUrl;
/**
* 图片消息媒体id可以调用多媒体文件下载接口拉取数据
*/
@XStreamAlias("MediaId")
private String mediaId; // 图片消息媒体id可以调用多媒体文件下载接口拉取数据
private String mediaId;
public String getPicUrl() {
return picUrl;

View File

@ -22,12 +22,21 @@ public class LinkMessage extends BaseMsg {
super(MessageType.link.name());
}
/**
* 消息标题
*/
@XStreamAlias("Title")
private String title; // 消息标题
private String title;
/**
* 消息描述
*/
@XStreamAlias("Description")
private String description; // 消息描述
@XStreamAlias("url")
private String url; // 消息链接
private String description;
/**
* 消息链接
*/
@XStreamAlias("Url")
private String url;
public String getTitle() {
return title;

View File

@ -24,14 +24,26 @@ public class LocationMessage extends BaseMsg {
super(MessageType.location.name());
}
/**
* 地理位置维度
*/
@XStreamAlias("Location_X")
private double x; // 地理位置维度
private double x;
/**
* 地理位置经度
*/
@XStreamAlias("Location_Y")
private double y; // 地理位置经度
private double y;
/**
* 地图缩放大小
*/
@XStreamAlias("Scale")
private double scale; // 地图缩放大小
private double scale;
/**
* 地理位置信息
*/
@XStreamAlias("Label")
private String label; // 地理位置信息
private String label;
public double getX() {
return x;
@ -49,10 +61,6 @@ public class LocationMessage extends BaseMsg {
return label;
}
public void setLabel(String label) {
this.label = label;
}
@Override
public String toString() {
return "LocationMessage [x=" + x + ", y=" + y + ", scale=" + scale

View File

@ -1 +1,10 @@
普通消息
普通消息
-------
当普通微信用户向公众账号发消息时微信服务器将POST消息的XML数据包到开发者填写的URL上。各消息类型的推送XML数据包结构如下
微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次
关于重试的消息排重推荐使用msgid排重。
假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。

View File

@ -1,39 +1,42 @@
package com.foxinmy.weixin4j.msg;
import com.foxinmy.weixin4j.model.BaseMsg;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 文本消息
*
* @className TextMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html#.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">订阅号服务号的文本消息</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#text.E6.B6.88.E6.81.AF">企业号的文本消息</a>
*/
public class TextMessage extends BaseMsg {
private static final long serialVersionUID = -7018053906644190260L;
public TextMessage() {
super(MessageType.text.name());
}
@XStreamAlias("Content")
private String content; // 消息内容
public String getContent() {
return content;
}
@Override
public String toString() {
return "TextMessage [content=" + content + ", " + super.toString()
+ "]";
}
}
package com.foxinmy.weixin4j.msg;
import com.foxinmy.weixin4j.model.BaseMsg;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 文本消息
*
* @className TextMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html#.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">订阅号服务号的文本消息</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#text.E6.B6.88.E6.81.AF">企业号的文本消息</a>
*/
public class TextMessage extends BaseMsg {
private static final long serialVersionUID = -7018053906644190260L;
public TextMessage() {
super(MessageType.text.name());
}
/**
* 消息内容
*/
@XStreamAlias("Content")
private String content;
public String getContent() {
return content;
}
@Override
public String toString() {
return "TextMessage [content=" + content + ", " + super.toString()
+ "]";
}
}

View File

@ -24,10 +24,16 @@ public class VideoMessage extends BaseMsg {
super(MessageType.video.name());
}
/**
* 视频消息媒体id可以调用多媒体文件下载接口拉取数据
*/
@XStreamAlias("MediaId")
private String mediaId; // 视频消息媒体id可以调用多媒体文件下载接口拉取数据
private String mediaId;
/**
* 视频消息缩略图的媒体id可以调用多媒体文件下载接口拉取数据
*/
@XStreamAlias("ThumbMediaId")
private String thumbMediaId; // 视频消息缩略图的媒体id可以调用多媒体文件下载接口拉取数据
private String thumbMediaId;
public String getMediaId() {
return mediaId;

View File

@ -27,13 +27,21 @@ public class VoiceMessage extends BaseMsg {
super(MessageType.voice.name());
}
/**
* 语音消息媒体id可以调用多媒体文件下载接口拉取数据
*/
@XStreamAlias("MediaId")
private String mediaId; // 语音消息媒体id可以调用多媒体文件下载接口拉取数据
private String mediaId;
/**
* 语音格式如amrspeex等
*/
@XStreamAlias("Format")
private String format; // 语音格式如amrspeex等
private String format;
/**
* 语音识别结果UTF8编码
*/
@XStreamAlias("Recognition")
private String recognition; // 语音识别结果UTF8编码
private String recognition;
public String getRecognition() {
return recognition;

View File

@ -10,9 +10,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @author jy
* @date 2014年12月28日
* @since JDK 1.7
* @see<a href=
* "http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6#.E7.94.A8.E6.88.B7.E8.BF.9B.E5.85.A5.E5.BA.94.E7.94.A8.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81"
* >用户进入应用的事件推送</a>
* @see <a href=
* "http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6#.E7.94.A8.E6.88.B7.E8.BF.9B.E5.85.A5.E5.BA.94.E7.94.A8.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81"
* >用户进入应用的事件推送</a>
*/
public class EnterAgentEventMessage extends EventMessage {
@ -22,8 +22,11 @@ public class EnterAgentEventMessage extends EventMessage {
super(EventType.enter_agent);
}
/**
* 事件KEY值与自定义菜单接口中KEY值对应
*/
@XStreamAlias("EventKey")
private String eventKey; // 事件KEY值与自定义菜单接口中KEY值对应
private String eventKey;
public String getEventKey() {
return eventKey;

View File

@ -26,6 +26,11 @@ public class EventMessage extends BaseMsg {
this.eventType = eventType;
}
/**
* 事件类型
*
* @see com.foxinmy.weixin4j.type.EventType
*/
@XStreamAlias("Event")
private EventType eventType;

View File

@ -21,17 +21,16 @@ public class KfCloseEventMessage extends EventMessage {
super(EventType.kf_close_session);
}
/**
* 客服账号
*/
@XStreamAlias("KfAccount")
private String kfAccount; // 客服账号
private String kfAccount;
public String getKfAccount() {
return kfAccount;
}
public void setKfAccount(String kfAccount) {
this.kfAccount = kfAccount;
}
@Override
public String toString() {
return "KfCloseEventMessage [kfAccount=" + kfAccount + ", ="

View File

@ -14,24 +14,23 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* href="http://mp.weixin.qq.com/wiki/2/6c20f3e323bdf5986cfcb33cbd3b829a.html#.E4.BC.9A.E8.AF.9D.E7.8A.B6.E6.80.81.E9.80.9A.E7.9F.A5.E4.BA.8B.E4.BB.B6">会话状态通知事件</a>
*/
public class KfCreateEventMessage extends EventMessage {
private static final long serialVersionUID = -8968189700999202108L;
public KfCreateEventMessage() {
super(EventType.kf_create_session);
}
/**
* 客服账号
*/
@XStreamAlias("KfAccount")
private String kfAccount; // 客服账号
private String kfAccount;
public String getKfAccount() {
return kfAccount;
}
public void setKfAccount(String kfAccount) {
this.kfAccount = kfAccount;
}
@Override
public String toString() {
return "KfCreateEventMessage [kfAccount=" + kfAccount + ", ="

View File

@ -20,29 +20,25 @@ public class KfSwitchEventMessage extends EventMessage {
public KfSwitchEventMessage() {
super(EventType.kf_switch_session);
}
/**
* 来自的客服账号
*/
@XStreamAlias("FromKfAccount")
private String fromKfAccount; // 来自的客服账号
private String fromKfAccount;
/**
* 转移给客服账号
*/
@XStreamAlias("ToKfAccount")
private String toKfAccount; // 转移给客服账号
private String toKfAccount;
public String getFromKfAccount() {
return fromKfAccount;
}
public void setFromKfAccount(String fromKfAccount) {
this.fromKfAccount = fromKfAccount;
}
public String getToKfAccount() {
return toKfAccount;
}
public void setToKfAccount(String toKfAccount) {
this.toKfAccount = toKfAccount;
}
@Override
public String toString() {
return "KfSwitchEventMessage [fromKfAccount=" + fromKfAccount

View File

@ -22,13 +22,21 @@ public class LocationEventMessage extends EventMessage {
public LocationEventMessage() {
super(EventType.location);
}
/**
* 地理位置纬度
*/
@XStreamAlias("Latitude")
private String latitude;// 地理位置纬度
private String latitude;
/**
* 地理位置经度
*/
@XStreamAlias("Longitude")
private String longitude;// 地理位置经度
private String longitude;
/**
* 地理位置精度
*/
@XStreamAlias("Precision")
private String precision;// 地理位置精度
private String precision;
public String getLatitude() {
return latitude;

View File

@ -25,14 +25,30 @@ public class MassEventMessage extends EventMessage {
super(EventType.masssendjobfinish);
}
/**
* 群发后的状态信息 send successsend failerr(num)
*/
@XStreamAlias("Status")
private String status;
/**
* group_id下粉丝数或者openid_list中的粉丝数
*/
@XStreamAlias("TotalCount")
private int totalCount;
/**
* 过滤过滤是指特定地区性别的过滤用户设置拒收的过滤用户接收已超4条的过滤准备发送的粉丝数原则上FilterCount =
* SentCount + ErrorCount
*/
@XStreamAlias("FilterCount")
private int filterCount;
/**
* 发送成功的粉丝数
*/
@XStreamAlias("SentCount")
private int sentCount;
/**
* 发送失败的粉丝数
*/
@XStreamAlias("ErrorCount")
private int errorCount;
@ -63,10 +79,9 @@ public class MassEventMessage extends EventMessage {
}
/**
* 发送状态描述</br>
* err(10001,涉嫌广告) err(20001,涉嫌政治) err(20004,涉嫌社会)</br>
* err(20002,涉嫌色情) err(20006,涉嫌违法犯罪) err(20008,涉嫌欺诈)</br>
* err(20013,涉嫌版权) err(22000,涉嫌互推(互相宣传) err(21000,涉嫌其他)
* 发送状态描述</br> err(10001,涉嫌广告) err(20001,涉嫌政治) err(20004,涉嫌社会)</br>
* err(20002,涉嫌色情) err(20006,涉嫌违法犯罪) err(20008,涉嫌欺诈)</br> err(20013,涉嫌版权)
* err(22000,涉嫌互推(互相宣传) err(21000,涉嫌其他)
*
* @param status
* @return 中文描述
@ -76,10 +91,9 @@ public class MassEventMessage extends EventMessage {
}
/**
* 发送状态描述</br>
* err(10001,涉嫌广告) err(20001,涉嫌政治) err(20004,涉嫌社会)</br>
* err(20002,涉嫌色情) err(20006,涉嫌违法犯罪) err(20008,涉嫌欺诈)</br>
* err(20013,涉嫌版权) err(22000,涉嫌互推(互相宣传) err(21000,涉嫌其他)
* 发送状态描述</br> err(10001,涉嫌广告) err(20001,涉嫌政治) err(20004,涉嫌社会)</br>
* err(20002,涉嫌色情) err(20006,涉嫌违法犯罪) err(20008,涉嫌欺诈)</br> err(20013,涉嫌版权)
* err(22000,涉嫌互推(互相宣传) err(21000,涉嫌其他)
*
* @param status
* @return 中文描述
@ -106,7 +120,7 @@ public class MassEventMessage extends EventMessage {
@Override
public String toString() {
return "MassEventMessage [status=" + status + ", totalCount="
return "MassEventMessage [status=" + getStatusDesc() + ", totalCount="
+ totalCount + ", filterCount=" + filterCount + ", sentCount="
+ sentCount + ", errorCount=" + errorCount + ", "
+ super.toString() + "]";

View File

@ -1 +1,10 @@
事件消息
事件消息
-------
当普通微信用户向公众账号发消息时微信服务器将POST消息的XML数据包到开发者填写的URL上。各消息类型的推送XML数据包结构如下
微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次
关于重试的消息排重推荐使用msgid排重。
假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。

View File

@ -15,6 +15,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
*/
public class ScanEventMessage extends EventMessage {
private static final long serialVersionUID = 8078674062833071562L;
public ScanEventMessage() {
super(EventType.scan);
}
@ -23,12 +25,16 @@ public class ScanEventMessage extends EventMessage {
super(eventType);
}
private static final long serialVersionUID = 8078674062833071562L;
/**
* 事件KEY值是一个32位无符号整数即创建二维码时的二维码scene_id
*/
@XStreamAlias("EventKey")
private String eventKey; // 事件KEY值是一个32位无符号整数即创建二维码时的二维码scene_id
private String eventKey;
/**
* 二维码的ticket可用来换取二维码图片
*/
@XStreamAlias("Ticket")
private String ticket; // 二维码的ticket可用来换取二维码图片
private String ticket;
public String getEventKey() {
return eventKey;

View File

@ -21,8 +21,11 @@ public class TemplatesendjobfinishMessage extends EventMessage {
super(EventType.templatesendjobfinish);
}
/**
* 推送状态 如failed: system failed
*/
@XStreamAlias("Status")
private String status; // 推送状态
private String status;
public String getStatus() {
return status;

View File

@ -28,8 +28,11 @@ public class MenuEventMessage extends EventMessage {
super(eventType);
}
/**
* 事件KEY值与自定义菜单接口中KEY值对应
*/
@XStreamAlias("EventKey")
private String eventKey; // 事件KEY值与自定义菜单接口中KEY值对应
private String eventKey;
public String getEventKey() {
return eventKey;

View File

@ -25,6 +25,9 @@ public class MenuLocationEventMessage extends MenuEventMessage {
super(EventType.location_select);
}
/**
* 发送的位置消息
*/
@XStreamAlias("SendLocationInfo")
private LocationInfo locationInfo;
@ -32,18 +35,41 @@ public class MenuLocationEventMessage extends MenuEventMessage {
return locationInfo;
}
/**
* 地理位置信息
* @className LocationInfo
* @author jy
* @date 2015年3月29日
* @since JDK 1.7
* @see
*/
public static class LocationInfo implements Serializable {
private static final long serialVersionUID = 4904181780216819965L;
/**
* 地理位置维度
*/
@XStreamAlias("Location_X")
private double x; // 地理位置维度
private double x;
/**
* 地理位置经度
*/
@XStreamAlias("Location_Y")
private double y; // 地理位置经度
private double y;
/**
* 地图缩放大小
*/
@XStreamAlias("Scale")
private double scale; // 地图缩放大小
private double scale;
/**
* 地理位置信息
*/
@XStreamAlias("Label")
private String label; // 地理位置信息
private String label;
/**
* 朋友圈POI的名字可能为空
*/
@XStreamAlias("Poiname")
private String poiname;

View File

@ -21,6 +21,9 @@ public class MenuPhotoEventMessage extends MenuEventMessage {
private static final long serialVersionUID = 3142350663022709730L;
/**
* 发送的图片信息
*/
@XStreamAlias("SendPicsInfo")
private PictureInfo pictureInfo;
@ -28,12 +31,27 @@ public class MenuPhotoEventMessage extends MenuEventMessage {
return pictureInfo;
}
/**
* 图片信息
*
* @className PictureInfo
* @author jy
* @date 2015年3月29日
* @since JDK 1.7
* @see
*/
public static class PictureInfo implements Serializable {
private static final long serialVersionUID = -3361375879168233258L;
/**
* 发送的图片数量
*/
@XStreamAlias("Count")
private int count;
/**
* 图片列表
*/
@XStreamAlias("PicList")
private List<PictureItem> items;
@ -51,11 +69,23 @@ public class MenuPhotoEventMessage extends MenuEventMessage {
}
}
/**
* 图片
*
* @className PictureItem
* @author jy
* @date 2015年3月29日
* @since JDK 1.7
* @see
*/
@XStreamAlias("item")
public static class PictureItem implements Serializable {
private static final long serialVersionUID = -7636697449096645590L;
/**
* 图片的MD5值开发者若需要可用于验证接收到图片
*/
@XStreamAlias("PicMd5Sum")
private String md5;

View File

@ -20,6 +20,9 @@ public class MenuScanEventMessage extends MenuEventMessage {
private static final long serialVersionUID = 3142350663022709730L;
/**
* 扫描信息
*/
@XStreamAlias("ScanCodeInfo")
private ScanInfo scanInfo;
@ -27,12 +30,26 @@ public class MenuScanEventMessage extends MenuEventMessage {
return scanInfo;
}
/**
* 扫描信息
*
* @className ScanInfo
* @author jy
* @date 2015年3月29日
* @since JDK 1.7
* @see
*/
public static class ScanInfo implements Serializable {
private static final long serialVersionUID = 2237570238164900421L;
/**
* 扫描类型一般是qrcode
*/
@XStreamAlias("ScanType")
private String type;
/**
* 扫描结果即二维码对应的字符串信息
*/
@XStreamAlias("ScanResult")
private String result;

View File

@ -1 +1,3 @@
底部菜单消息
菜单消息
用户点击自定义菜单后微信会把点击事件推送给开发者请注意点击菜单弹出子菜单不会产生上报。请注意第3个到第8个的所有事件仅支持微信iPhone5.4.1以上版本和Android5.4以上版本的微信用户,旧版本微信用户点击后将没有回应,开发者也不能正常接收到事件推送。

View File

@ -17,17 +17,29 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
public class Article implements Serializable {
private static final long serialVersionUID = -1231352700301456395L;
/**
* 图文消息标题
*/
@XStreamAlias("Title")
private String title; // 图文消息标题
private String title;
/**
* 图文消息描述
*/
@JSONField(name = "description")
@XStreamAlias("Description")
private String desc; // 图文消息描述
private String desc;
/**
* 图片链接支持JPGPNG格式较好的效果为大图360*200小图200*200
*/
@JSONField(name = "picurl")
@XStreamAlias("PicUrl")
private String picUrl; // 图片链接支持JPGPNG格式较好的效果为大图360*200小图200*200
private String picUrl;
/**
* 点击图文消息跳转链接
*/
@XStreamAlias("Url")
private String url; // 点击图文消息跳转链接
private String url;
public Article(String title, String desc, String picUrl, String url) {
this.title = title;
@ -73,4 +85,4 @@ public class Article implements Serializable {
return "Article [title=" + title + ", desc=" + desc + ", picUrl="
+ picUrl + ", url=" + url + "]";
}
}
}

View File

@ -19,6 +19,9 @@ public class Base implements Serializable {
private static final long serialVersionUID = 8487251213352068227L;
/**
* 媒体类型
*/
@JSONField(serialize = false)
@XStreamOmitField
private MediaType mediaType;

View File

@ -19,6 +19,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
public class File extends Base implements Notifyable {
private static final long serialVersionUID = -8149837316289636110L;
/**
* 上传后的微信返回的媒体ID
*/
@JSONField(name = "media_id")
@XStreamAlias("MediaId")
private String mediaId;

View File

@ -20,6 +20,9 @@ public class Image extends Base implements Responseable, Notifyable, Massable {
private static final long serialVersionUID = 6928681900960656161L;
/**
* 上传后的微信返回的媒体ID
*/
@JSONField(name = "media_id")
@XStreamAlias("MediaId")
private String mediaId;

View File

@ -15,16 +15,37 @@ public class MpArticle implements Serializable {
private static final long serialVersionUID = 5583479943661639234L;
/**
* 图文消息缩略图的media_id可以在基础支持-上传多媒体文件接口中获得 非空
*/
@JSONField(name = "thumb_media_id")
private String thumbMediaId; // 图文消息缩略图的media_id可以在基础支持-上传多媒体文件接口中获得 非空
private String author;// 图文消息的作者 可为空
private String title;// 图文消息的标题 非空
private String thumbMediaId;
/**
* 图文消息的作者 可为空
*/
private String author;
/**
* 图文消息的标题 非空
*/
private String title;
/**
* 在图文消息页面点击阅读原文后的页面 可为空
*/
@JSONField(name = "content_source_url")
private String url;// 在图文消息页面点击阅读原文后的页面 可为空
private String content;// 图文消息页面的内容支持HTML标签 非空
private String digest;// 图文消息的描述 可为空
private String url;
/**
* 图文消息页面的内容支持HTML标签 非空
*/
private String content;
/**
* 图文消息的描述 可为空
*/
private String digest;
/**
* 是否显示封面1为显示0为不显示 可为空
*/
@JSONField(name = "show_cover_pic")
private String showCoverPic; // 是否显示封面1为显示0为不显示 可为空
private String showCoverPic;
public MpArticle(String thumbMediaId, String title, String content) {
this.thumbMediaId = thumbMediaId;

View File

@ -24,9 +24,15 @@ public class MpNews extends Base implements Massable, Notifyable {
private static final long serialVersionUID = 8853054484809101524L;
/**
* 上传图文列表后微信返回的媒体ID
*/
@JSONField(name = "media_id")
@XStreamAlias("MediaId")
private String mediaId;
/**
* 图文列表
*/
@JSONField(name = "articles")
@XStreamOmitField
private List<MpArticle> articles;

View File

@ -20,6 +20,9 @@ public class MpVideo extends Base implements Massable {
private static final long serialVersionUID = 2167437425244069128L;
/**
* 上传视频后微信返回的媒体ID
*/
@JSONField(name = "media_id")
@XStreamAlias("MediaId")
private String mediaId;

View File

@ -20,17 +20,32 @@ public class Music extends Base implements Responseable, Notifyable {
private static final long serialVersionUID = -5952134916367253297L;
/**
* 音乐标题
*/
@XStreamAlias("Title")
private String title;
/**
* 音乐描述
*/
@JSONField(name = "description")
@XStreamAlias("Description")
private String desc;
/**
* 音乐链接
*/
@JSONField(name = "musicurl")
@XStreamAlias("MusicUrl")
private String musicUrl;
/**
* 高质量音乐链接WIFI环境优先使用该链接播放音乐
*/
@JSONField(name = "hqmusicurl")
@XStreamAlias("HQMusicUrl")
private String hqMusicUrl;
/**
* 缩略图的媒体id通过上传多媒体文件得到的id
*/
@JSONField(name = "thumb_media_id")
@XStreamAlias("ThumbMediaId")
private String thumbMediaId;

View File

@ -24,6 +24,11 @@ public class News extends Base implements Responseable, Notifyable {
private static final int MAX_ARTICLE_COUNT = 10;
private static final long serialVersionUID = 3348756809039388415L;
/**
* 图文列表
*
* @see com.foxinmy.weixin4j.msg.model.Article
*/
@JSONField(name = "articles")
@XStreamAlias("Articles")
private List<Article> articles;

View File

@ -1 +1,9 @@
不同的消息类型中的模型
不同的消息类型中的消息对象
[被动消息](http://mp.weixin.qq.com/wiki/14/89b871b5466b19b3efa4ada8e577d45e.html)
[客服消息](http://mp.weixin.qq.com/wiki/1/70a29afed17f56d537c833f89be979c9.html#.E5.AE.A2.E6.9C.8D.E6.8E.A5.E5.8F.A3-.E5.8F.91.E6.B6.88.E6.81.AF)
[群发消息](http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html)
[模板消息](http://mp.weixin.qq.com/wiki/17/304c1885ea66dbedf7dc170d84999a9d.html)

View File

@ -20,6 +20,9 @@ public class Text extends Base implements Responseable, Notifyable, Massable {
private static final long serialVersionUID = 520050144519064503L;
/**
* 内容
*/
private String content;
public Text(String content) {

View File

@ -20,7 +20,9 @@ public class Trans extends Base implements Responseable {
private static final long serialVersionUID = -214711609286629729L;
// 指定会话接入的客服账号
/**
* 指定会话接入的客服账号
*/
@XStreamAlias("KfAccount")
private String kfAccount;

View File

@ -3,6 +3,7 @@ package com.foxinmy.weixin4j.msg.model;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.type.MediaType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
/**
* 视频对象
@ -20,13 +21,26 @@ public class Video extends Base implements Responseable, Notifyable {
private static final long serialVersionUID = 2167437425244069128L;
/**
* 上传视频微信返回的媒体ID
*/
@JSONField(name = "media_id")
@XStreamAlias("MediaId")
private String mediaId;
/**
* 缩略图的媒体ID(客服消息)
*/
@XStreamOmitField
@JSONField(name = "thumb_media_id")
private String thumbMediaId;
/**
* 视频标题
*/
@XStreamAlias("Title")
private String title;
/**
* 视频描述
*/
@JSONField(name = "description")
@XStreamAlias("Description")
private String desc;

View File

@ -5,30 +5,65 @@ import java.io.Serializable;
import com.foxinmy.weixin4j.type.EncryptType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 微信的被动消息
*
* @className HttpWeixinMessage
* @author jy
* @date 2015年3月29日
* @since JDK 1.7
* @see
*/
@XStreamAlias("xml")
public class HttpWeixinMessage implements Serializable {
private static final long serialVersionUID = -9157395300510879866L;
// 以下字段是加密方式为安全模式时的参数
/**
* 公众号的唯一ID
*/
@XStreamAlias("ToUserName")
private String toUserName;
/**
* 加密后的内容
*/
@XStreamAlias("Encrypt")
private String encryptContent;
/**
* 加密类型
*
* @see com.foxinmy.weixin4j.type.EncryptType
*/
private EncryptType encryptType;
// 以下字段每次被动消息时都会带上
/**
* 随机字符串
*/
private String echoStr;
/**
* 时间戳
*/
private String timeStamp;
/**
* 随机数
*/
private String nonce;
/**
* 参数签名
*/
private String signature;
// 冗余字段
/**
* 设置的token
*/
private String token;
// xml消息明文主体
/**
* xml消息明文主体
*/
private String originalContent;
// request method
/**
* 请求的方式
*/
private String method;
public String getToUserName() {
@ -113,11 +148,11 @@ public class HttpWeixinMessage implements Serializable {
@Override
public String toString() {
return "HttpWeixinMessage [toUserName=" + toUserName + ", encryptContent="
+ encryptContent + ", encryptType=" + encryptType
+ ", echoStr=" + echoStr + ", timeStamp=" + timeStamp
+ ", nonce=" + nonce + ", signature=" + signature + ", token="
+ token + ", originalContent=" + originalContent + ", method="
+ method + "]";
return "HttpWeixinMessage [toUserName=" + toUserName
+ ", encryptContent=" + encryptContent + ", encryptType="
+ encryptType + ", echoStr=" + echoStr + ", timeStamp="
+ timeStamp + ", nonce=" + nonce + ", signature=" + signature
+ ", token=" + token + ", originalContent=" + originalContent
+ ", method=" + method + "]";
}
}

View File

@ -55,7 +55,15 @@ public class ResponseMessage extends BaseMsg {
xmlStream.addImplicitCollection(News.class, "articles");
xmlStream.aliasSystemAttribute(null, "class");
}
private String attach; // 附加数据
/**
* 附加数据
*/
private String attach;
/**
* 消息对象
*
* @see com.foxinmy.weixin4j.msg.model.Responseable
*/
private final Base box;
public ResponseMessage(Base box) {

View File

@ -2,6 +2,7 @@ package com.foxinmy.weixin4j.type;
/**
* 消息加密类型
*
* @className EncryptType
* @author jy
* @date 2014年11月23日
@ -9,5 +10,12 @@ package com.foxinmy.weixin4j.type;
* @see
*/
public enum EncryptType {
RAW, AES
/**
* 明文模式
*/
RAW,
/**
* 密文模式
*/
AES;
}

View File

@ -25,21 +25,114 @@ import com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage;
* @see
*/
public enum EventType {
subscribe(ScribeEventMessage.class), unsubscribe(ScribeEventMessage.class), scan(
ScanEventMessage.class), scancode_push(MenuScanEventMessage.class), view(
MenuEventMessage.class), scancode_waitmsg(
MenuScanEventMessage.class), pic_sysphoto(
MenuPhotoEventMessage.class), pic_photo_or_album(
MenuPhotoEventMessage.class), pic_weixin(
MenuPhotoEventMessage.class), location_select(
MenuLocationEventMessage.class), click(MenuEventMessage.class), location(
LocationEventMessage.class), masssendjobfinish(
MassEventMessage.class), templatesendjobfinish(
TemplatesendjobfinishMessage.class), enter_agent(
EnterAgentEventMessage.class), kf_create_session(
KfCreateEventMessage.class), kf_close_session(
KfCloseEventMessage.class), kf_switch_session(
KfSwitchEventMessage.class);
/**
* 关注事件
*
* @see com.foxinmy.weixin4j.msg.event.ScribeEventMessage
*/
subscribe(ScribeEventMessage.class),
/**
* 取消关注事件
*
* @see com.foxinmy.weixin4j.msg.event.ScribeEventMessage
*/
unsubscribe(ScribeEventMessage.class),
/**
* 二维码扫描事件
*
* @see com.foxinmy.weixin4j.msg.event.ScanEventMessage
*/
scan(ScanEventMessage.class),
/**
* 上报地理位置事件
*
* @see com.foxinmy.weixin4j.msg.event.LocationEventMessage
*/
location(LocationEventMessage.class),
/**
* 菜单扫描事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage
*/
scancode_push(MenuScanEventMessage.class),
/**
* 菜单点击关键字事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage
*/
view(MenuEventMessage.class),
/**
* 菜单点击链接事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage
*/
click(MenuEventMessage.class),
/**
* 菜单扫描并调出等待界面事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage
*/
scancode_waitmsg(MenuScanEventMessage.class),
/**
* 菜单弹出拍照事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage
*/
pic_sysphoto(MenuPhotoEventMessage.class),
/**
* 菜单弹出发图事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage
*/
pic_photo_or_album(MenuPhotoEventMessage.class),
/**
* 菜单弹出发图事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage
*/
pic_weixin(MenuPhotoEventMessage.class),
/**
* 菜单发送地理位置事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuLocationEventMessage
*/
location_select(MenuLocationEventMessage.class),
/**
* 群发消息事件
*
* @see com.foxinmy.weixin4j.msg.event.MassEventMessage
*/
masssendjobfinish(MassEventMessage.class),
/**
* 模板消息事件
*
* @see com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage
*/
templatesendjobfinish(TemplatesendjobfinishMessage.class),
/**
* 进入企业号应用事件
*
* @see com.foxinmy.weixin4j.msg.event.EnterAgentEventMessage
*/
enter_agent(EnterAgentEventMessage.class),
/**
* 客服接入会话事件
*
* @see com.foxinmy.weixin4j.msg.event.KfCreateEventMessage
*/
kf_create_session(KfCreateEventMessage.class),
/**
* 客服关闭会话事件
*
* @see com.foxinmy.weixin4j.msg.event.KfCloseEventMessage
*/
kf_close_session(KfCloseEventMessage.class),
/**
* 客服转接会话事件
*
* @see com.foxinmy.weixin4j.msg.event.KfSwitchEventMessage
*/
kf_switch_session(KfSwitchEventMessage.class);
private Class<? extends EventMessage> eventClass;

View File

@ -17,10 +17,48 @@ import com.foxinmy.weixin4j.msg.event.EventMessage;
*
*/
public enum MessageType {
text(TextMessage.class), image(ImageMessage.class), voice(
VoiceMessage.class), video(VideoMessage.class), location(
LocationMessage.class), link(LinkMessage.class), event(
EventMessage.class);
/**
* 文字消息
*
* @see com.foxinmy.weixin4j.msg.TextMessage
*/
text(TextMessage.class),
/**
* 图片消息
*
* @see com.foxinmy.weixin4j.msg.ImageMessage
*/
image(ImageMessage.class),
/**
* 语音消息
*
* @see com.foxinmy.weixin4j.msg.VoiceMessage
*/
voice(VoiceMessage.class),
/**
* 视频消息
*
* @see com.foxinmy.weixin4j.msg.VideoMessage
*/
video(VideoMessage.class),
/**
* 位置消息
*
* @see com.foxinmy.weixin4j.msg.LocationMessage
*/
location(LocationMessage.class),
/**
* 链接消息
*
* @see com.foxinmy.weixin4j.msg.LinkMessage
*/
link(LinkMessage.class),
/**
* 事件消息
*
* @see com.foxinmy.weixin4j.msg.event.EventMessage
*/
event(EventMessage.class);
private Class<? extends BaseMsg> messageClass;
MessageType(Class<? extends BaseMsg> messageClass) {

View File

@ -1 +0,0 @@
消息类型、事件类型等枚举

View File

@ -25,6 +25,12 @@ import com.foxinmy.weixin4j.model.Consts;
*/
public class ClassUtil {
/**
* 获取某个包下所有的class信息
*
* @param _package 包对象
* @return
*/
public static Set<Class<?>> getClasses(Package _package) {
String packageName = _package.getName();
String packageFileName = packageName.replace(".", File.separator);
@ -47,6 +53,13 @@ public class ClassUtil {
return null;
}
/**
* 实例化目录下所有的class对象
*
* @param dir 文件目录
* @param packageName 包的全限类名
* @return
*/
private static Set<Class<?>> findClassesByFile(File dir, String packageName) {
Set<Class<?>> classes = new HashSet<Class<?>>();
File[] files = dir.listFiles(new FilenameFilter() {
@ -75,6 +88,13 @@ public class ClassUtil {
return classes;
}
/**
* 实例化jar包下所有的class对象
*
* @param jar jar包对象
* @param packageName 包的全限类名
* @return
*/
private static Set<Class<?>> findClassesByJar(JarFile jar,
String packageName) {
Set<Class<?>> classes = new HashSet<Class<?>>();

View File

@ -19,18 +19,46 @@ public class DateUtil {
private static final String yyyy_MM_dd = "yyyy-MM-dd";
private static final String yyyyMMddHHmmss = "yyyyMMddHHmmss";
/**
* 日期对象转换为yyyymmdd的字符串形式
*
* @param date
* 日期对象
* @return
*/
public static String fortmat2yyyyMMdd(Date date) {
return new SimpleDateFormat(yyyyMMdd).format(date);
}
/**
* 日期对象转换为yyyy_mm_dd的字符串形式
*
* @param date
* 日期对象
* @return
*/
public static String fortmat2yyyy_MM_dd(Date date) {
return new SimpleDateFormat(yyyy_MM_dd).format(date);
}
/**
* 日期对象转换为yyyymmddhhmmss的字符串形式
*
* @param date
* 日期对象
* @return
*/
public static String fortmat2yyyyMMddHHmmss(Date date) {
return new SimpleDateFormat(yyyyMMddHHmmss).format(date);
}
/**
* yyyymmddhhmmss形式的字符串转换为日期对象
*
* @param date
* 日期字符串
* @return
*/
public static Date parse2yyyyMMddHHmmss(String date) {
try {
return new SimpleDateFormat(yyyyMMddHHmmss).parse(date);
@ -40,10 +68,22 @@ public class DateUtil {
return null;
}
/**
* 单位为分的金额格式化为元的字符串形式
*
* @param fee
* 金额 单位为分
* @return
*/
public static String formaFee2Fen(double fee) {
return new DecimalFormat("#").format(fee * 100);
}
/**
* 当前时间戳转换为秒的字符串形式
*
* @return
*/
public static String timestamp2string() {
return String.valueOf(System.currentTimeMillis() / 1000);
}

View File

@ -23,6 +23,14 @@ import com.alibaba.fastjson.TypeReference;
* @see
*/
public class MapUtil {
/**
* 连接字符串
* @param object 对象
* @param encoder 是否编码
* @param lowerCase 是否转换小写
* @param extra 附加对象
* @return
*/
public static String toJoinString(Object object, boolean encoder,
boolean lowerCase, Map<String, String> extra) {
String text = JSON.toJSONString(object);
@ -43,6 +51,13 @@ public class MapUtil {
return toJoinString(map, encoder, lowerCase);
}
/**
* 连接字符串
* @param map 对象
* @param encoder 是否编码
* @param lowerCase 是否转换小写
* @return
*/
public static String toJoinString(Map<String, String> map, boolean encoder,
boolean lowerCase) {
StringBuilder sb = new StringBuilder();

View File

@ -5,6 +5,7 @@ import java.util.UUID;
/**
* 随机码工具类
*
* @className RandomUtil
* @author jy
* @date 2014年10月22日
@ -17,7 +18,13 @@ public class RandomUtil {
private static final String LETTERCHAR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String NUMBERCHAR = "0123456789";
// 返回一个定长的随机字符串(包含数字和大小写字母)
/**
* 返回一个定长的随机字符串(包含数字和大小写字母)
*
* @param length
* 随机数的长度
* @return
*/
public static String generateString(int length) {
StringBuilder sb = new StringBuilder(length);
Random random = new Random();
@ -27,7 +34,13 @@ public class RandomUtil {
return sb.toString();
}
// 返回一个定长的随机纯数字字符串(只包含数字)
/**
* 返回一个定长的随机纯数字字符串(只包含数字)
*
* @param length
* 随机数的长度
* @return
*/
public static String generateStringByNumberChar(int length) {
StringBuilder sb = new StringBuilder(length);
Random random = new Random();
@ -37,7 +50,13 @@ public class RandomUtil {
return sb.toString();
}
// 返回一个定长的随机纯字母字符串(只包含大小写字母)
/**
* 返回一个定长的随机纯字母字符串(只包含大小写字母)
*
* @param length
* 随机数的长度
* @return
*/
public static String generateStringByLetterCharr(int length) {
StringBuilder sb = new StringBuilder(length);
Random random = new Random();
@ -47,12 +66,24 @@ public class RandomUtil {
return sb.toString();
}
// 返回一个定长的随机纯大写字母字符串(只包含大小写字母)
/**
* 返回一个定长的随机纯大写字母字符串(只包含大小写字母)
*
* @param length
* 随机数的长度
* @return
*/
public static String generateLowerString(int length) {
return generateStringByLetterCharr(length).toLowerCase();
}
// 返回一个定长的随机纯小写字母字符串(只包含大小写字母)
/**
* 返回一个定长的随机纯小写字母字符串(只包含大小写字母)
*
* @param length
* 随机数的长度
* @return
*/
public static String generateUpperString(int length) {
return generateStringByLetterCharr(length).toUpperCase();
}

View File

@ -15,12 +15,23 @@ import org.apache.commons.lang3.StringUtils;
*/
public class ReflectionUtil {
// 获取包包名
/**
* 获取包包名
*
* @param obj
* @return
*/
public static String getPackageName(Object obj) {
return obj.getClass().getPackage().getName();
}
// 获取字段的泛型参数类型
/**
* 获取字段的泛型参数类型
*
* @param obj
* @param fieldName
* @return
*/
public static Class<?> getFieldGenericType(Object obj, String fieldName) {
Field field = getAccessibleField(obj, fieldName);
Type type = field.getGenericType();

View File

@ -14,6 +14,15 @@ import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.mapper.Mapper;
/**
* Map转换为实体对象
*
* @className Map2ObjectConverter
* @author jy
* @date 2015年3月29日
* @since JDK 1.7
* @see
*/
public class Map2ObjectConverter extends MapConverter {
public Map2ObjectConverter(Mapper mapper) {

View File

@ -32,6 +32,8 @@ weixin4j-mp
+ Pay3Api `V3支付API`
+ CouponApi `代金券API`
+ DataApi `数据统计API`
+ OauthApi `oauth授权API`
@ -196,4 +198,10 @@ weixin4j-mp
+ **weixin4j-mp-server**: 新增客服创建、关闭、转接会话事件
+ **weixin4j-mp-server**: 新增deploy.xml远程部署ant脚本
+ **weixin4j-mp-server**: 新增deploy.xml远程部署ant脚本
* 2015-03-29
+ **weixin4j-mp-api**: 单行注释调整为多行文档注释
+ **weixin4j-mp-api**: 新增(CouponApi)[./weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/CouponApi.java]代金券接口

View File

@ -31,6 +31,8 @@ weixin4j-mp-api
* Pay3Api `V3支付API`
* CouponApi `代金券API`
* DataApi `数据统计API`
* OauthApi `oauth授权API`
@ -171,4 +173,10 @@ weixin.properties说明
* 2015-03-25
+ 根据《微信商户平台文档》修缮[Pay3Api](./weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/Pay3Api.java)类
+ 根据《微信商户平台文档》修缮[Pay3Api](./weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/Pay3Api.java)类
* 2015-03-29
+ 单行注释调整为多行文档注释
+ 新增(CouponApi)[./src/main/java/com/foxinmy/weixin4j/mp/api/CouponApi.java]代金券接口

View File

@ -7,9 +7,13 @@ import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.http.XmlResult;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.api.CouponApi;
import com.foxinmy.weixin4j.mp.api.Pay2Api;
import com.foxinmy.weixin4j.mp.api.Pay3Api;
import com.foxinmy.weixin4j.mp.api.PayApi;
import com.foxinmy.weixin4j.mp.payment.coupon.CouponDetail;
import com.foxinmy.weixin4j.mp.payment.coupon.CouponResult;
import com.foxinmy.weixin4j.mp.payment.coupon.CouponStock;
import com.foxinmy.weixin4j.mp.payment.v3.ApiResult;
import com.foxinmy.weixin4j.mp.type.BillType;
import com.foxinmy.weixin4j.mp.type.CurrencyType;
@ -34,9 +38,11 @@ import com.foxinmy.weixin4j.util.ConfigUtil;
* @see <a href="http://pay.weixin.qq.com/wiki/doc/api/index.html">商户平台支付API</a>
*/
public class WeixinPayProxy {
private final PayApi payApi;
private final Pay2Api pay2Api;
private final Pay3Api pay3Api;
private final CouponApi couponApi;
public WeixinPayProxy() {
this(ConfigUtil.getWeixinMpAccount(), new FileTokenHolder(
@ -60,6 +66,7 @@ public class WeixinPayProxy {
} else {
this.payApi = this.pay3Api;
}
this.couponApi = new CouponApi(weixinAccount);
}
/**
@ -293,7 +300,7 @@ public class WeixinPayProxy {
* @see com.foxinmy.weixin4j.mp.api.Pay3Api
* @see <a
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4">申请退款API</a>
* @since V3 TODO
* @since V3
* @throws WeixinException
*/
public com.foxinmy.weixin4j.mp.payment.v3.RefundResult refundV3(
@ -471,4 +478,77 @@ public class WeixinPayProxy {
return pay3Api.interfaceReport(interfaceUrl, executeTime, outTradeNo,
ip, time, returnXml);
}
/**
* 发放代金券(需要证书)
*
* @param caFile
* 证书文件(后缀为*.p12)
* @param couponStockId
* 代金券批次id
* @param partnerTradeNo
* 商户发放凭据号格式商户id+日期+流水号商户侧需保持唯一性
* @param openId
* 用户的openid
* @param opUserId
* 操作员帐号, 默认为商户号 可在商户平台配置操作员对应的api权限 可为空
* @return 发放结果
* @see com.foxinmy.weixin4j.mp.api.CouponApi
* @see com.foxinmy.weixin4j.mp.payment.coupon.CouponResult
* @see <a
* href="http://pay.weixin.qq.com/wiki/doc/api/sp_coupon.php?chapter=12_3">发放代金券接口</a>
* @throws WeixinException
*/
public CouponResult sendCoupon(File caFile, String couponStockId,
String partnerTradeNo, String openId, String opUserId)
throws WeixinException {
return couponApi.sendCoupon(caFile, couponStockId, partnerTradeNo,
openId, opUserId);
}
/**
* 发放代金券采用properties中配置的ca文件
*
* @see {@link com.foxinmy.weixin4j.mp.WeixinPayProxy#sendCoupon(File, String, String, String, String)}
*/
public CouponResult sendCoupon(String couponStockId, String partnerTradeNo,
String openId) throws WeixinException {
File caFile = new File(ConfigUtil.getClassPathValue("ca_file"));
return couponApi.sendCoupon(caFile, couponStockId, partnerTradeNo,
openId, null);
}
/**
* 查询代金券批次
*
* @param couponStockId
* 代金券批次ID
* @return 代金券批次信息
* @see com.foxinmy.weixin4j.mp.api.CouponApi
* @see com.foxinmy.weixin4j.mp.payment.coupon.CouponStock
* @see <a
* href="http://pay.weixin.qq.com/wiki/doc/api/sp_coupon.php?chapter=12_4">查询代金券信息</a>
* @throws WeixinException
*/
public CouponStock queryCouponStock(String couponStockId)
throws WeixinException {
return couponApi.queryCouponStock(couponStockId);
}
/**
* 查询代金券详细
*
* @param couponId
* 代金券ID
* @return 代金券详细信息
* @see com.foxinmy.weixin4j.mp.api.CouponApi
* @see com.foxinmy.weixin4j.mp.payment.coupon.CouponDetail
* @see <a
* href="http://pay.weixin.qq.com/wiki/doc/api/sp_coupon.php?chapter=12_5">查询代金券详细信息</a>
* @throws WeixinException
*/
public CouponDetail queryCouponDetail(String couponId)
throws WeixinException {
return couponApi.queryCouponDetail(couponId);
}
}

View File

@ -349,7 +349,7 @@ public class WeixinProxy {
* 客服消息对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html">发送客服消息</a>
* href="http://mp.weixin.qq.com/wiki/1/70a29afed17f56d537c833f89be979c9.html#.E5.AE.A2.E6.9C.8D.E6.8E.A5.E5.8F.A3-.E5.8F.91.E6.B6.88.E6.81.AF">发送客服消息</a>
* @see com.foxinmy.weixin4j.msg.model.Text
* @see com.foxinmy.weixin4j.msg.model.Image
* @see com.foxinmy.weixin4j.msg.model.Voice

View File

@ -0,0 +1,169 @@
package com.foxinmy.weixin4j.mp.api;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.http.SSLHttpRequest;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.payment.PayUtil;
import com.foxinmy.weixin4j.mp.payment.coupon.CouponDetail;
import com.foxinmy.weixin4j.mp.payment.coupon.CouponResult;
import com.foxinmy.weixin4j.mp.payment.coupon.CouponStock;
import com.foxinmy.weixin4j.util.RandomUtil;
/**
* 代金券API
*
* @className CouponApi
* @author jy
* @date 2015年3月25日
* @since JDK 1.7
* @see <a href="http://pay.weixin.qq.com/wiki/doc/api/sp_coupon.php">代金券文档</a>
*/
public class CouponApi extends MpApi {
private final WeixinMpAccount weixinAccount;
public CouponApi(WeixinMpAccount weixinAccount) {
this.weixinAccount = weixinAccount;
}
/**
* 发放代金券(需要证书)
*
* @param caFile
* 证书文件(后缀为*.p12)
* @param couponStockId
* 代金券批次id
* @param partnerTradeNo
* 商户发放凭据号格式商户id+日期+流水号商户侧需保持唯一性
* @param openId
* 用户的openid
* @param opUserId
* 操作员帐号, 默认为商户号 可在商户平台配置操作员对应的api权限 可为空
* @return 发放结果
* @see com.foxinmy.weixin4j.mp.payment.coupon.CouponResult
* @see <a
* href="http://pay.weixin.qq.com/wiki/doc/api/sp_coupon.php?chapter=12_3">发放代金券接口</a>
* @throws WeixinException
*/
public CouponResult sendCoupon(File caFile, String couponStockId,
String partnerTradeNo, String openId, String opUserId)
throws WeixinException {
Map<String, String> map = baseMap();
map.put("coupon_stock_id", couponStockId);
map.put("partner_trade_no", partnerTradeNo);
map.put("openid", openId);
// openid记录数目前支持num=1
map.put("openid_count", "1");
// 操作员帐号, 默认为商户号 可在商户平台配置操作员对应的api权限
if (StringUtils.isBlank(opUserId)) {
opUserId = weixinAccount.getMchId();
}
map.put("op_user_id", opUserId);
map.put("version", "1.0");
map.put("type", "XML");
String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey());
map.put("sign", sign);
String param = map2xml(map);
String coupon_send_uri = getRequestUri("coupon_send_uri");
Response response = null;
InputStream ca = null;
try {
ca = new FileInputStream(caFile);
SSLHttpRequest request = new SSLHttpRequest(
weixinAccount.getMchId(), ca);
response = request.post(coupon_send_uri, param);
} catch (WeixinException e) {
throw e;
} catch (Exception e) {
throw new WeixinException(e.getMessage());
} finally {
if (ca != null) {
try {
ca.close();
} catch (IOException e) {
;
}
}
}
return response.getAsObject(new TypeReference<CouponResult>() {
});
}
/**
* 查询代金券批次
*
* @param couponStockId
* 代金券批次ID
* @return 代金券批次信息
* @see com.foxinmy.weixin4j.mp.payment.coupon.CouponStock
* @see <a
* href="http://pay.weixin.qq.com/wiki/doc/api/sp_coupon.php?chapter=12_4">查询代金券批次信息</a>
* @throws WeixinException
*/
public CouponStock queryCouponStock(String couponStockId)
throws WeixinException {
Map<String, String> map = baseMap();
map.put("coupon_stock_id", couponStockId);
String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey());
map.put("sign", sign);
String param = map2xml(map);
String couponstock_query_uri = getRequestUri("couponstock_query_uri");
Response response = request.post(couponstock_query_uri, param);
return response.getAsObject(new TypeReference<CouponStock>() {
});
}
/**
* 查询代金券详细
*
* @param couponId
* 代金券ID
* @return 代金券详细信息
* @see com.foxinmy.weixin4j.mp.payment.coupon.CouponDetail
* @see <a
* href="http://pay.weixin.qq.com/wiki/doc/api/sp_coupon.php?chapter=12_5">查询代金券详细信息</a>
* @throws WeixinException
*/
public CouponDetail queryCouponDetail(String couponId)
throws WeixinException {
Map<String, String> map = baseMap();
map.put("coupon_id", couponId);
String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey());
map.put("sign", sign);
String param = map2xml(map);
String coupondetail_query_uri = getRequestUri("coupondetail_query_uri");
Response response = request.post(coupondetail_query_uri, param);
return response.getAsObject(new TypeReference<CouponDetail>() {
});
}
/**
* 接口请求基本数据
*
* @return
*/
private Map<String, String> baseMap() {
Map<String, String> map = new HashMap<String, String>();
map.put("appid", weixinAccount.getId());
map.put("mch_id", weixinAccount.getMchId());
map.put("nonce_str", RandomUtil.generateString(16));
if (StringUtils.isNotBlank(weixinAccount.getDeviceInfo())) {
map.put("device_info", weixinAccount.getDeviceInfo());
}
if (StringUtils.isNotBlank(weixinAccount.getSubMchId())) {
map.put("sub_mch_id", weixinAccount.getSubMchId());
}
return map;
}
}

View File

@ -16,7 +16,7 @@ import com.foxinmy.weixin4j.token.TokenHolder;
* @date 2014年9月26日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html">客服消息</a>
* href="http://mp.weixin.qq.com/wiki/1/70a29afed17f56d537c833f89be979c9.html#.E5.AE.A2.E6.9C.8D.E6.8E.A5.E5.8F.A3-.E5.8F.91.E6.B6.88.E6.81.AF">客服消息</a>
* @see com.foxinmy.weixin4j.mp.message.NotifyMessage
*/
public class NotifyApi extends MpApi {
@ -34,7 +34,7 @@ public class NotifyApi extends MpApi {
* 客服消息对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html">发送客服消息</a>
* href="http://mp.weixin.qq.com/wiki/1/70a29afed17f56d537c833f89be979c9.html#.E5.AE.A2.E6.9C.8D.E6.8E.A5.E5.8F.A3-.E5.8F.91.E6.B6.88.E6.81.AF">发送客服消息</a>
* @see com.foxinmy.weixin4j.msg.model.Text
* @see com.foxinmy.weixin4j.msg.model.Image
* @see com.foxinmy.weixin4j.msg.model.Voice

View File

@ -47,7 +47,7 @@ import com.foxinmy.weixin4j.util.DateUtil;
import com.foxinmy.weixin4j.util.RandomUtil;
/**
* V3支付API
* V3(商户平台版)支付API
*
* @className Pay3Api
* @author jy

View File

@ -1 +1,29 @@
API的实现
* MediaApi `上传/下载媒体文件API`
* NotifyApi `客服消息API`
* CustomApi `多客服API`
* MassApi `群发消息API`
* UserApi `用户管理API`
* GroupApi `分组管理API`
* MenuApi `底部菜单API`
* QrApi `二维码API`
* TmplApi `模板消息API`
* HelperApi `辅助API`
* Pay2Api `V2支付API`
* Pay3Api `V3支付API`
* CouponApi `代金券API`
* DataApi `数据统计API`
* OauthApi `oauth授权API`

View File

@ -159,4 +159,13 @@ material_media_del_uri={api_cgi_url}/material/del_material?access_token=%s
# \u83b7\u53d6\u5a92\u4f53\u7d20\u6750\u603b\u6570
material_media_count_uri={api_cgi_url}/material/get_materialcount?access_token=%s
# \u83b7\u53d6\u5a92\u4f53\u7d20\u6750\u5217\u8868
material_media_list_uri={api_cgi_url}/material/batchget_material?access_token=%s
material_media_list_uri={api_cgi_url}/material/batchget_material?access_token=%s
# \u53d1\u653e\u4ee3\u91d1\u5238
coupon_send_uri={mch_base_url}/mmpaymkttransfers/send_coupon
# \u67e5\u8be2\u4ee3\u91d1\u5238\u6279\u6b21\u4fe1\u606f
couponstock_query_uri={mch_base_url}/mmpaymkttransfers/query_coupon_stock
# \u67e5\u8be2\u4ee3\u91d1\u5238\u8be6\u7ec6\u4fe1\u606f
coupondetail_query_uri={mch_base_url}/promotion/query_coupon
# \u53d1\u73b0\u91d1\u7ea2\u5305
redpack_send_uri={mch_base_url}/mmpaymkttransfers/sendredpack

View File

@ -4,26 +4,59 @@ import java.io.Serializable;
import com.alibaba.fastjson.annotation.JSONField;
/**
* 图文数据
*
* @className ArticleDatacube1
* @author jy
* @date 2015年3月29日
* @since JDK 1.7
* @see
*/
public class ArticleDatacube1 implements Serializable {
private static final long serialVersionUID = 4140706754295502971L;
/**
* 图文页点击群发图文卡片进入的页面的阅读人数
*/
@JSONField(name = "int_page_read_user")
private int intPageReadUser;// 图文页点击群发图文卡片进入的页面的阅读人数
private int intPageReadUser;
/**
* 图文页的阅读次数
*/
@JSONField(name = "int_page_read_count")
private int intPageReadCount;// 图文页的阅读次数
private int intPageReadCount;
/**
* 原文页点击图文页阅读原文进入的页面的阅读人数无原文页时此处数据为0
*/
@JSONField(name = "ori_page_read_user")
private int oriPageReadUser;// 原文页点击图文页阅读原文进入的页面的阅读人数无原文页时此处数据为0
private int oriPageReadUser;
/**
* 原文页的阅读次数
*/
@JSONField(name = "ori_page_read_count")
private int oriPageReadCount;// 原文页的阅读次数
private int oriPageReadCount;
/**
* 分享的人数
*/
@JSONField(name = "shareUser")
private int shareUser; // 分享的人数
private int shareUser;
/**
* 分享的次数
*/
@JSONField(name = "shareCount")
private int shareCount;// 分享的次数
private int shareCount;
/**
* 收藏的人数
*/
@JSONField(name = "add_to_fav_user")
private int favUser;// 收藏的人数
private int favUser;
/**
* 收藏的次数
*/
@JSONField(name = "add_to_fav_count")
private int favCount;// 收藏的次数
private int favCount;
public int getIntPageReadUser() {
return intPageReadUser;

View File

@ -4,11 +4,26 @@ import java.util.Date;
import com.alibaba.fastjson.annotation.JSONField;
/**
* 图文数据
*
* @className ArticleDatacube2
* @author jy
* @date 2015年3月29日
* @since JDK 1.7
* @see
*/
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;
@ -33,5 +48,4 @@ public class ArticleDatacube2 extends ArticleDatacube1 {
return "statDate=" + statDate + ", targetUser=" + targetUser + ", "
+ super.toString();
}
}

View File

@ -1,12 +1,14 @@
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.ShareSourceType;
/**
* 数据统计:图文分享数据
*
* @className ArticleDatacubeShare
* @author jy
* @date 2015年1月30日
@ -16,22 +18,37 @@ import com.foxinmy.weixin4j.mp.type.ShareSourceType;
public class ArticleDatacubeShare implements Serializable {
private static final long serialVersionUID = 3841239305410294553L;
/**
* 数据的日期
*/
@JSONField(name = "ref_date")
private String refDate; // 数据的日期
private Date refDate;
/**
* 数据的小时包括从000到2300分别代表的是[000,100)[2300,2400)即每日的第1小时和最后1小时
*/
@JSONField(name = "ref_hour")
private int refHour; // 数据的小时包括从000到2300分别代表的是[000,100)[2300,2400)即每日的第1小时和最后1小时
private int refHour;
/**
* 分享的人数
*/
@JSONField(name = "shareUser")
private int shareUser; // 分享的人数
private int shareUser;
/**
* 分享的次数
*/
@JSONField(name = "shareCount")
private int shareCount;// 分享的次数
private int shareCount;
/**
* 分享的场景
*/
@JSONField(name = "share_scene")
private int shareScene;// 分享的场景
private int shareScene;
public String getRefDate() {
public Date getRefDate() {
return refDate;
}
public void setRefDate(String refDate) {
public void setRefDate(Date refDate) {
this.refDate = refDate;
}

View File

@ -1,5 +1,7 @@
package com.foxinmy.weixin4j.mp.datacube;
import java.util.Date;
import com.alibaba.fastjson.annotation.JSONField;
/**
@ -13,22 +15,31 @@ import com.alibaba.fastjson.annotation.JSONField;
*/
public class ArticleSummary extends ArticleDatacube1 {
private static final long serialVersionUID = 4820605570501368550L;
/**
* 数据的日期
*/
@JSONField(name = "ref_date")
private String refDate; // 数据的日期
private Date refDate;
/**
* 数据的小时包括从000到2300分别代表的是[000,100)[2300,2400)即每日的第1小时和最后1小时
*/
@JSONField(name = "ref_hour")
private int refHour; // 数据的小时包括从000到2300分别代表的是[000,100)[2300,2400)即每日的第1小时和最后1小时
private int refHour;
/**
* 这里的msgid实际上是由msgid图文消息id和index消息次序索引组成 例如12003_3
* 其中12003是msgid即一次群发的id消息的 3为index假设该次群发的图文消息共5个文章因为可能为多图文 3表示5个中的第3个
*/
private String msgid;
private String title;// 图文消息的标题
/**
* 图文消息的标题
*/
private String title;
public String getRefDate() {
public Date getRefDate() {
return refDate;
}
public void setRefDate(String refDate) {
public void setRefDate(Date refDate) {
this.refDate = refDate;
}

View File

@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.mp.datacube;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import com.alibaba.fastjson.annotation.JSONField;
@ -17,21 +18,30 @@ import com.alibaba.fastjson.annotation.JSONField;
public class ArticleTotal implements Serializable {
private static final long serialVersionUID = -6820948857241500950L;
/**
* 数据的日期
*/
@JSONField(name = "ref_date")
private String refDate; // 数据的日期
private Date refDate;
/**
* 这里的msgid实际上是由msgid图文消息id和index消息次序索引组成 例如12003_3
* 其中12003是msgid即一次群发的id消息的 3为index假设该次群发的图文消息共5个文章因为可能为多图文 3表示5个中的第3个
*/
private String msgid;
private String title;// 图文消息的标题
/**
* 图文消息的标题
*/
private String title;
/**
* 详细信息
*/
private List<ArticleDatacube2> details;
public String getRefDate() {
public Date getRefDate() {
return refDate;
}
public void setRefDate(String refDate) {
public void setRefDate(Date refDate) {
this.refDate = refDate;
}

View File

@ -18,18 +18,36 @@ public class InterfaceSummary implements Serializable {
private static final long serialVersionUID = -8812979112580350988L;
/**
* 引用的日期
*/
@JSONField(name = "ref_date")
private Date refDate; // 引用的日期
private Date refDate;
/**
* 数据的小时包括从000到2300分别代表的是[000,100)[2300,2400)即每日的第1小时和最后1小时
*/
@JSONField(name = "ref_hour")
private int refHour; // 数据的小时包括从000到2300分别代表的是[000,100)[2300,2400)即每日的第1小时和最后1小时
private int refHour;
/**
* 通过服务器配置地址获得消息后被动回复用户消息的次数
*/
@JSONField(name = "callback_count")
private int callbackCount; // 通过服务器配置地址获得消息后被动回复用户消息的次数
private int callbackCount;
/**
* 上述动作的失败次数
*/
@JSONField(name = "fail_count")
private int failCount; // 上述动作的失败次数
private int failCount;
/**
* 总耗时除以callback_count即为平均耗时
*/
@JSONField(name = "total_time_cost")
private int totalTimeCost;// 总耗时除以callback_count即为平均耗时
private int totalTimeCost;
/**
* 最大耗时
*/
@JSONField(name = "max_time_cost")
private int maxTimeCost;// 最大耗时
private int maxTimeCost;
public Date getRefDate() {
return refDate;

View File

@ -18,16 +18,32 @@ import com.foxinmy.weixin4j.type.MessageType;
public class UpstreamMsg implements Serializable {
private static final long serialVersionUID = -2605207523094962029L;
/**
* 引用的日期
*/
@JSONField(name = "ref_date")
private Date refDate; // 引用的日期
private Date refDate;
/**
* 数据的小时包括从000到2300分别代表的是[000,100)[2300,2400)即每日的第1小时和最后1小时
*/
@JSONField(name = "ref_hour")
private int refHour; // 数据的小时包括从000到2300分别代表的是[000,100)[2300,2400)即每日的第1小时和最后1小时
private int refHour;
/**
* 消息类型
*/
@JSONField(name = "msg_type")
private int msgType; // 消息类型
private int msgType;
/**
* 上行发送了向公众号发送了消息的用户数
*/
@JSONField(name = "msg_user")
private int msgUser; // 上行发送了向公众号发送了消息的用户数
private int msgUser;
/**
* 上行发送了消息的消息总数
*/
@JSONField(name = "msg_count")
private int msgCount;// 上行发送了消息的消息总数
private int msgCount;
public Date getRefDate() {
return refDate;

View File

@ -4,6 +4,7 @@ import java.io.Serializable;
import java.util.Date;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.mp.type.DatacuteCountIntervalType;
/**
* 数据统计:消息发送分布数据
@ -17,10 +18,16 @@ import com.alibaba.fastjson.annotation.JSONField;
public class UpstreamMsgDist implements Serializable {
private static final long serialVersionUID = -2605207523094962029L;
/**
* 引用的日期
*/
@JSONField(name = "ref_date")
private Date refDate; // 引用的日期
private Date refDate;
/**
* 上行发送了向公众号发送了消息的用户数
*/
@JSONField(name = "msg_user")
private int msgUser; // 上行发送了向公众号发送了消息的用户数
private int msgUser;
/**
* 当日发送消息量分布的区间0代表 01代表1-52代表6-103代表10次以上
*/
@ -43,8 +50,8 @@ public class UpstreamMsgDist implements Serializable {
this.msgUser = msgUser;
}
public int getCountInterval() {
return countInterval;
public DatacuteCountIntervalType getCountInterval() {
return DatacuteCountIntervalType.values()[countInterval];
}
public void setCountInterval(int countInterval) {

View File

@ -18,17 +18,31 @@ import com.foxinmy.weixin4j.mp.type.UserSourceType;
public class UserSummary implements Serializable {
private static final long serialVersionUID = 5303181828798568052L;
/**
* 数据的日期
*/
@JSONField(name = "ref_date")
private Date refDate; // 数据的日期
private Date refDate;
/**
* 用户的渠道
*/
@JSONField(name = "user_source")
private int userSource; // 用户的渠道数值代表的含义如下0代表其他 30代表扫二维码 17代表名片分享
// 35代表搜号码即微信添加朋友页的搜索 39代表查询微信公众帐号 43代表图文页右上角菜单
private int userSource;
/**
* 新增的用户数量
*/
@JSONField(name = "new_user")
private int newUser; // 新增的用户数量
private int newUser;
/**
* 取消关注的用户数量new_user减去cancel_user即为净增用户数量
*/
@JSONField(name = "cancel_user")
private int cancelUser; // 取消关注的用户数量new_user减去cancel_user即为净增用户数量
private int cancelUser;
/**
* 总用户量
*/
@JSONField(name = "cumulate_user")
private int cumulateUser; // 总用户量
private int cumulateUser;
public Date getRefDate() {
return refDate;

View File

@ -20,15 +20,21 @@ import com.foxinmy.weixin4j.msg.model.Base;
* @see com.foxinmy.weixin4j.msg.model.Music
* @see com.foxinmy.weixin4j.msg.model.News
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF">发送客服消息</a>
* href="http://mp.weixin.qq.com/wiki/1/70a29afed17f56d537c833f89be979c9.html#.E5.AE.A2.E6.9C.8D.E6.8E.A5.E5.8F.A3-.E5.8F.91.E6.B6.88.E6.81.AF">发送客服消息</a>
*/
public class NotifyMessage implements Serializable {
private static final long serialVersionUID = 7190233634431087729L;
/**
* 用户的openid
*/
private String touser;
/**
* 消息对象
*/
@JSONField(name = "%s")
private Base box;// 消息项
private Base box;
public NotifyMessage(Base box) {
this(null, box);

View File

@ -1,5 +1,3 @@
NotifyMessage: 客服消息
NotifyMessage: (客服消息)[http://mp.weixin.qq.com/wiki/1/70a29afed17f56d537c833f89be979c9.html#.E5.AE.A2.E6.9C.8D.E6.8E.A5.E5.8F.A3-.E5.8F.91.E6.B6.88.E6.81.AF]
ResponseMessage: 被动消息
TemplateMessage: 模板消息
TemplateMessage: (模板消息)[http://mp.weixin.qq.com/wiki/17/304c1885ea66dbedf7dc170d84999a9d.html]

View File

@ -12,16 +12,31 @@ import java.util.Map;
* @date 2014年9月29日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AF%E6%8E%A5%E5%8F%A3">模板消息</a>
* href="http://mp.weixin.qq.com/wiki/17/304c1885ea66dbedf7dc170d84999a9d.html">模板消息</a>
*/
public class TemplateMessage implements Serializable {
private static final long serialVersionUID = 7950608393821661436L;
/**
* 用户的openid
*/
private String touser;
/**
* 模板ID
*/
private String template_id;
/**
* 点击消息跳转的url
*/
private String url;
/**
* 顶部的颜色值
*/
private String topcolor = "#FF0000";
/**
* 数据项
*/
private Map<String, Item> data;
public void pushData(String key, String value) {
@ -37,9 +52,24 @@ public class TemplateMessage implements Serializable {
pushData("first", title);
}
/**
* 模板消息的数据项
*
* @className Item
* @author jy
* @date 2015年3月29日
* @since JDK 1.7
* @see
*/
private static class Item implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 字段值
*/
private String value;
/**
* 颜色值
*/
private String color;
public Item(String value) {

View File

@ -16,11 +16,27 @@ import com.foxinmy.weixin4j.mp.type.CustomRecordOperCode;
public class CustomRecord implements Serializable {
private static final long serialVersionUID = -4024147769411601325L;
private String worker;// 客服账号
private String openid;// 用户的标识
private CustomRecordOperCode opercode;// 操作ID会话状态
private Date time;// 操作时间
private String text;// 聊天记录
/**
* 客服账号
*/
private String worker;
/**
* 用户的标识
*/
private String openid;
/**
* 操作ID会话状态
*/
private CustomRecordOperCode opercode;
/**
* 操作时间
*/
private Date time;
/**
* 聊天记录
*/
private String text;
public String getWorker() {
return worker;

View File

@ -8,6 +8,7 @@ import com.alibaba.fastjson.annotation.JSONField;
/**
* 关注信息
*
* @author jy.hu
* @date 2014年4月4日
* @since JDK 1.7
@ -16,12 +17,29 @@ public class Following implements Serializable {
private static final long serialVersionUID = 1917454368271027134L;
/**
* 关注总数
*/
private int total;
/**
* 拉取的OPENID个数最大值为10000
*/
private int count;
/**
* 列表数据OPENID的列表
*/
@JSONField(name = "data")
private JSONObject dataJson;
/**
* 拉取列表的后一个用户的OPENID
*/
@JSONField(name = "next_openid")
private String nextOpenId;
/**
* 用户详情列表
*
* @see com.foxinmy.weixin4j.mp.model.User
*/
private List<User> userList;
public int getTotal() {

View File

@ -13,8 +13,17 @@ public class Group implements Serializable {
private static final long serialVersionUID = 6979565973974005954L;
/**
* 分组id由微信分配
*/
private int id;
/**
* 分组名
*/
private String name;
/**
* 分组内用户数量
*/
private int count;
public int getId() {

View File

@ -18,22 +18,42 @@ public class KfAccount implements Serializable {
private static final long serialVersionUID = -4565570894727129245L;
/**
* 客服账号@微信别名 微信别名如有修改旧账号返回旧的微信别名新增的账号返回新的微信别名
*/
@JSONField(name = "kf_account")
// 客服账号@微信别名 微信别名如有修改旧账号返回旧的微信别名新增的账号返回新的微信别名
private String account;
/**
* 客服昵称
*/
@JSONField(name = "kf_nick")
private String nickName;// 客服昵称
private String nickName;
/**
* 客服工号
*/
@JSONField(name = "kf_id")
private String id;// 客服工号
private String id;
/**
* 客服头像
*/
@JSONField(name = "kf_headimg")
private String headImg; //客服头像
private String headImg;
// 以下字段是调用在线客服状态返回的字段
private KfOnlineStatus status; // 客服在线状态 1pc在线2手机在线 若pc和手机同时在线则为 1+2=3
/**
* 客服在线状态 1pc在线2手机在线 若pc和手机同时在线则为 1+2=3
*/
private KfOnlineStatus status;
/**
* 客服设置的最大自动接入数
*/
@JSONField(name = "auto_accept")
private int autoAccept;// 客服设置的最大自动接入数
private int autoAccept;
/**
* 客服当前正在接待的会话数
*/
@JSONField(name = "accepted_case")
private int acceptedCase;// 客服当前正在接待的会话数
private int acceptedCase;
public String getAccount() {
return account;

View File

@ -18,12 +18,21 @@ public class KfSession implements Serializable {
private static final long serialVersionUID = 7236468333492555458L;
/**
* 客服账号
*/
@JSONField(name = "kf_account")
private String kfAccount; // 客服账号
private String kfAccount;
/**
* 用户ID
*/
@JSONField(name = "openid")
private String userOpenId; // 用户ID
private String userOpenId;
/**
* 创建时间
*/
@JSONField(name = "createtime")
private Date createTime; // 创建时间
private Date createTime;
public String getKfAccount() {
return kfAccount;

View File

@ -17,14 +17,26 @@ public class MediaCounter implements Serializable {
private static final long serialVersionUID = -1752502821323552783L;
/**
* 语音总数量
*/
@JSONField(name = "voice_count")
private long voiceCount;// 语音总数量
private long voiceCount;
/**
* 视频总数量
*/
@JSONField(name = "video_count")
private long videoCount;// 视频总数量
private long videoCount;
/**
* 图片总数量
*/
@JSONField(name = "image_count")
private long imageCount; // 图片总数量
private long imageCount;
/**
* 图文总数量
*/
@JSONField(name = "news_count")
private long newsCount; // 图文总数量
private long newsCount;
public long getVoiceCount() {
return voiceCount;

View File

@ -20,13 +20,25 @@ public class MediaItem implements Serializable {
private static final long serialVersionUID = -2923028664954250134L;
/**
* 媒体素材ID
*/
@JSONField(name = "media_id")
private String mediaId; // 媒体素材ID
private String name; // 媒体素材名称
private String mediaId;
/**
* 媒体素材名称
*/
private String name;
/**
* 媒体素材最后更新时间
*/
@JSONField(name = "update_time")
private Date updateTime; // 媒体素材最后更新时间
private Date updateTime;
/**
* 图文素材列表
*/
@JSONField(name = "news_item")
private List<MpArticle> articles; // 图文素材列表
private List<MpArticle> articles;
public String getMediaId() {
return mediaId;

View File

@ -19,14 +19,26 @@ public class MediaRecord implements Serializable {
private static final long serialVersionUID = 7017503153256241457L;
/**
* 该类型的素材的总数
*/
@JSONField(name = "total_count")
private int totalCount;// 该类型的素材的总数
private int totalCount;
/**
* 本次调用获取的素材的数量
*/
@JSONField(name = "item_count")
private int itemCount;// 本次调用获取的素材的数量
private int itemCount;
/**
* 媒体类型
*/
@JSONField(serialize = false)
private MediaType mediaType; // 媒体类型
private MediaType mediaType;
/**
* 媒体信息
*/
@JSONField(name = "item")
private List<MediaItem> items; // 媒体信息
private List<MediaItem> items;
public int getTotalCount() {
return totalCount;

View File

@ -17,8 +17,14 @@ public class OauthToken extends Token {
private static final long serialVersionUID = 1L;
/**
* 用户的openi
*/
private String openid;
/**
* 刷新token时的凭证
*/
@JSONField(name = "refresh_token")
private String refreshToken;

View File

@ -22,9 +22,18 @@ public class QRParameter implements Serializable {
private static final long serialVersionUID = 6611187606558274253L;
private int expireSeconds; // 该二维码有效时间以秒为单位 最大不超过1800
private QRType qrType; // 二维码类型QR_SCENE为临时,QR_LIMIT_SCENE为永久
private int sceneId; // 场景值ID临时二维码时为32位非0整型永久二维码时最大值为100000目前参数只支持1--100000
/**
* 该二维码有效时间以秒为单位 最大不超过1800
*/
private int expireSeconds;
/**
* 二维码类型QR_SCENE为临时,QR_LIMIT_SCENE为永久
*/
private QRType qrType;
/**
* 场景值ID临时二维码时为32位非0整型永久二维码时最大值为100000目前参数只支持1--100000
*/
private int sceneId;
public int getExpireSeconds() {
return expireSeconds;

View File

@ -19,19 +19,33 @@ public class SemQuery implements Serializable {
private static final long serialVersionUID = 679548284525912436L;
private JSONObject jsonObj;
// 输入文本串
/**
* 输入文本串
*
* @param query
*/
public SemQuery(String query) {
jsonObj = new JSONObject();
jsonObj.put("query", query);
}
// 城市名称,与经纬度二选一传入
/**
* 城市名称,与经纬度二选一传入
*
* @param city
* @return
*/
public SemQuery city(String city) {
jsonObj.put("city", city);
return this;
}
// 需要使用的服务类别,多个用,隔开,不能为空
/**
* 需要使用的服务类别,多个用,隔开,不能为空
*
* @param categorys
* @return
*/
public SemQuery category(SemCategory... categorys) {
StringBuilder category = new StringBuilder();
if (categorys.length == 1) {
@ -46,33 +60,59 @@ public class SemQuery implements Serializable {
return this;
}
// App id,开发者的唯一标识,用于区分开放者, 如果为空,则没法使用上下文理解功能
/**
* App id,开发者的唯一标识,用于区分开放者, 如果为空,则没法使用上下文理解功能
*
* @param appid
* @return
*/
public SemQuery appid(String appid) {
jsonObj.put("appid", appid);
return this;
}
// 用户唯一 id(并非开发者 id),用于区分该开发者下不同用户,如果为空,则没法使用上下文理解功能appid uid
// 同时存在的情况下,才可以使用上下文理解功能
/**
* 用户唯一 id(并非开发者 id),用于区分该开发者下不同用户,如果为空,则没法使用上下文理解功能appid
* uid同时存在的情况下,才可以使用上下文理解功能
*
* @param uid
* @return
*/
public SemQuery uid(String uid) {
jsonObj.put("uid", uid);
return this;
}
// 区域名称,在城市存在的情况下可省;与经纬度 二选一传入
/**
* 区域名称,在城市存在的情况下可省;与经纬度 二选一传入
*
* @param region
* @return
*/
public SemQuery region(String region) {
jsonObj.put("region", region);
return this;
}
// 纬度经度;与城市二选一传入
/**
* 纬度经度;与城市二选一传入
*
* @param latitude
* @param longitude
* @return
*/
public SemQuery location(float latitude, float longitude) {
jsonObj.put("latitude", latitude);
jsonObj.put("longitude", longitude);
return this;
}
// 输入文本串
/**
* 输入文本串
*
* @param query
* @return
*/
public static SemQuery build(String query) {
return new SemQuery(query);
}

View File

@ -17,17 +17,29 @@ import com.foxinmy.weixin4j.http.JsonResult;
public class SemResult extends JsonResult {
private static final long serialVersionUID = 9051214458161068387L;
// 用户的输入字符串
/**
* 用户的输入字符串
*/
private String query;
// 服务的全局类型id详见协议文档中垂直服务协议定义
/**
* 服务的全局类型id详见协议文档中垂直服务协议定义
*/
private String type;
// 语义理解后的结构化标识各服务不同
/**
* 语义理解后的结构化标识各服务不同
*/
private JSONObject semantic;
// 部分类别的结果
/**
* 部分类别的结果
*/
private JSONArray result;
// 部分类别的结果html5展示目前不支持
/**
* 部分类别的结果html5展示目前不支持
*/
private String answer;
// 特殊回复说明
/**
* 特殊回复说明
*/
private String text;
public String getQuery() {

View File

@ -24,21 +24,57 @@ public class User implements Serializable {
private static final long serialVersionUID = 1638176217299286265L;
private String openid; // 用户的唯一标识
private String nickname; // 用户昵称
/**
* 用户的唯一标识
*/
private String openid;
/**
* 用户昵称
*/
private String nickname;
/**
* 用户的性别值为1时是男性值为2时是女性值为0时是未知
*/
@JSONField(name = "sex")
private Gender gender; // 用户的性别值为1时是男性值为2时是女性值为0时是未知
private String province; // 用户个人资料填写的省份
private String city; // 普通用户个人资料填写的城市
private String country; // 国家如中国为CN
private String headimgurl; // 用户头像最后一个数值代表正方形头像大小有0466496132数值可选0代表640*640正方形头像用户没有头像时该项为空
private String privilege; // 用户特权信息json 数组如微信沃卡用户为chinaunicom
private Gender gender;
/**
* 用户个人资料填写的省份
*/
private String province;
/**
* 普通用户个人资料填写的城市
*/
private String city;
/**
* 国家如中国为CN
*/
private String country;
/**
* 用户头像最后一个数值代表正方形头像大小有0466496132数值可选0代表640*640正方形头像用户没有头像时该项为空
*/
private String headimgurl;
/**
* 用户特权信息json 数组如微信沃卡用户为chinaunicom
*/
private String privilege;
/**
* 用户是否订阅该公众号标识值为0时代表此用户没有关注该公众号拉取不到其余信息
*/
@JSONField(name = "subscribe")
private boolean isSubscribe; // 用户是否订阅该公众号标识值为0时代表此用户没有关注该公众号拉取不到其余信息
private boolean isSubscribe;
/**
* 关注时间
*/
@JSONField(name = "subscribe_time")
private Date subscribeTime; // 关注时间
private Lang language; // 使用语言
private String unionid; // 只有在用户将公众号绑定到微信开放平台帐号后才会出现该字段
private Date subscribeTime;
/**
* 使用语言
*/
private Lang language;
/**
* 只有在用户将公众号绑定到微信开放平台帐号后才会出现该字段
*/
private String unionid;
public String getOpenid() {
return openid;

View File

@ -1,5 +1,6 @@
package com.foxinmy.weixin4j.mp.payment;
import com.alibaba.fastjson.annotation.JSONField;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
@ -15,9 +16,14 @@ public class JsPayNotify extends PayBaseInfo {
private static final long serialVersionUID = -4659030958445259803L;
/**
* 用户的openid
*/
@XStreamAlias("OpenId")
private String openid; // 用户ID
private String openid;
/**
* 是否关注公众号
*/
@XStreamAlias("IsSubscribe")
private int issubscribe;
@ -37,9 +43,14 @@ public class JsPayNotify extends PayBaseInfo {
this.issubscribe = issubscribe;
}
@JSONField(serialize = false, deserialize = false)
public boolean getFormatIssubscribe() {
return issubscribe == 1;
}
@Override
public String toString() {
return "openid=" + openid + ", issubscribe=" + issubscribe
return "openid=" + openid + ", issubscribe=" + getFormatIssubscribe()
+ ", " + super.toString();
}
}

View File

@ -20,21 +20,38 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
public class MicroPayPackage extends PayPackage {
private static final long serialVersionUID = 8944928173669656177L;
private String appid; // 微信分配的公众账号 必须
/**
* 微信分配的公众账号 必须
*/
private String appid;
/**
* 微信支付分配的商户号 必须
*/
@XStreamAlias("mch_id")
@JSONField(name = "mch_id")
private String mchId; // 微信支付分配的商户号 必须
private String mchId;
/**
* 微信支付分配的终端设备号 非必须
*/
@XStreamAlias("device_info")
@JSONField(name = "device_info")
private String deviceInfo; // 微信支付分配的终端设备号 非必须
private String deviceInfo;
/**
* 随机字符串,不长于 32 必须
*/
@XStreamAlias("nonce_str")
@JSONField(name = "nonce_str")
private String nonceStr; // 随机字符串,不长于 32 必须
private String sign; // 签名 必须
private String nonceStr;
/**
* 签名 <font color="red">调用者不必关注</font>
*/
private String sign;
/**
* 扫码支付授权码 ,设备读取用户微信中的条码或者二维码信息
*/
@XStreamAlias("auth_code")
@JSONField(name = "auth_code")
private String authCode; // 扫码支付授权码 ,设备读取用 户微信中的条码或者二维码 信息
private String authCode;
public MicroPayPackage() {
@ -82,7 +99,7 @@ public class MicroPayPackage extends PayPackage {
return deviceInfo;
}
public void setDevice_info(String deviceInfo) {
public void setDeviceInfo(String deviceInfo) {
this.deviceInfo = deviceInfo;
}

View File

@ -2,6 +2,7 @@ package com.foxinmy.weixin4j.mp.payment;
import java.io.Serializable;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.mp.type.SignType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
@ -17,20 +18,32 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
public class PayBaseInfo implements Serializable {
private static final long serialVersionUID = 1843024880782466990L;
/**
* 公众号ID
*/
@XStreamAlias("AppId")
private String appId; // 公众号ID
private String appId;
/**
* 时间戳
*/
@XStreamAlias("TimeStamp")
private String timeStamp; // 时间戳
private String timeStamp;
/**
* 随机字符串
*/
@XStreamAlias("NonceStr")
private String nonceStr; // 随机字符串
private String nonceStr;
/**
* 签名结果
*/
@XStreamAlias("AppSignature")
private String paySign; // 签名结果
private String paySign;
/**
* 签名方式
*/
@XStreamAlias("SignMethod")
private String signType; // 签名方式
private String signType;
public String getAppId() {
return appId;
@ -68,6 +81,11 @@ public class PayBaseInfo implements Serializable {
return signType;
}
@JSONField(serialize = false, deserialize = false)
public SignType getFormatSignType() {
return SignType.valueOf(signType.toUpperCase());
}
public void setSignType(SignType signType) {
if (signType != null) {
this.signType = signType.name();
@ -87,8 +105,7 @@ public class PayBaseInfo implements Serializable {
@Override
public String toString() {
return "appId=" + appId + ", timeStamp=" + timeStamp
+ ", nonceStr=" + nonceStr + ", paySign=" + paySign
+ ", signType=" + signType;
return "appId=" + appId + ", timeStamp=" + timeStamp + ", nonceStr="
+ nonceStr + ", paySign=" + paySign + ", signType=" + signType;
}
}

View File

@ -20,34 +20,62 @@ public class PayPackage implements Serializable {
private static final long serialVersionUID = 3450161267802545790L;
private String body; // 商品描述 必须
private String detail; // 商品详情 非必须
private String attach; // 附加数据,原样返回 非必须
/**
* 商品描述 必须
*/
private String body;
/**
* 商品详情 非必须
*/
private String detail;
/**
* 附加数据,原样返回 非必须
*/
private String attach;
/**
* 商户系统内部的订单号 ,32 个字符内 可包含字母 ,确保 在商户系统唯一 必须
*/
@XStreamAlias("out_trade_no")
@JSONField(name = "out_trade_no")
private String outTradeNo; // 商户系统内部的订单号 ,32 个字符内 可包含字母 ,确保 在商户系统唯一 必须
private String outTradeNo;
/**
* 订单总金额,单位为分,不能带小数点 必须
*/
@XStreamAlias("total_fee")
@JSONField(name = "total_fee")
private String totalFee; // 订单总金额,单位为分, 能带小数点 必须
private String totalFee;
/**
* 订单生成的机器 IP 必须
*/
@XStreamAlias("spbill_create_ip")
@JSONField(name = "spbill_create_ip")
private String spbillCreateIp; // 订单生成的机器 IP 必须
private String spbillCreateIp;
/**
* 订单生成时间,格式为 yyyyMMddHHmmss, 2009 12月25日9点10分10秒表示为 20091225091010时区
* GMT+8 beijing该时间取 自商户服务器 非必须
*/
@XStreamAlias("time_start")
@JSONField(name = "time_start")
private String timeStart; // 订单生成时间,格式 yyyyMMddHHmmss, 2009
// 12月25日9点10分10秒表 示为 20091225091010时区 GMT+8
// beijing该时间取 自商户服务器 非必须
private String timeStart;
/**
* 订单失效时间,格为 yyyyMMddHHmmss, 2009 12月27日9点10分10秒表示为 20091227091010时区
* GMT+8 beijing该时间取 自商户服务商品标记 非必须
*/
@XStreamAlias("time_expire")
@JSONField(name = "time_expire")
private String timeExpire; // 订单失效时间,格式 yyyyMMddHHmmss, 2009
// 12月27日9点10分10秒表 示为 20091227091010时区 GMT+8
// beijing该时间取 自商户服务商品标记 非必须
private String timeExpire;
/**
* 商品标记,该字段不能随便填,不使用请填空 非必须
*/
@XStreamAlias("goods_tag")
@JSONField(name = "goods_tag")
private String goodsTag; // 商品标记,该字段不能随便 ,不使用请填空 非必须
private String goodsTag;
/**
* 通知地址接收微信支付成功通知 必须
*/
@XStreamAlias("notify_url")
@JSONField(name = "notify_url")
private String notifyUrl; // 通知地址接收微信支付成功通知 必须
private String notifyUrl;
public String getBody() {
return body;
@ -85,6 +113,12 @@ public class PayPackage implements Serializable {
return totalFee;
}
/**
* <font color="red">单位为元,自动格式化为分</font>
*
* @param totalFee
* 订单总额 单位为元
*/
public void setTotalFee(double totalFee) {
this.totalFee = DateUtil.formaFee2Fen(totalFee);
}
@ -142,6 +176,28 @@ public class PayPackage implements Serializable {
public PayPackage() {
}
/**
* 订单对象
*
* @param body
* 订单描述
* @param attach
* 附加数据
* @param outTradeNo
* 商户内部ID
* @param totalFee
* 订单总额 <font color="red">单位为元</font>
* @param spbillCreateIp
* 生成订单数据的机器IP
* @param timeStart
* 订单生成时间
* @param timeExpire
* 订单失效时间
* @param goodsTag
* 订单标记
* @param notifyUrl
* 回调地址
*/
public PayPackage(String body, String attach, String outTradeNo,
double totalFee, String spbillCreateIp, Date timeStart,
Date timeExpire, String goodsTag, String notifyUrl) {

View File

@ -9,7 +9,9 @@ public class PayRequest extends PayBaseInfo {
private static final long serialVersionUID = -453746488398523883L;
// 订单详情扩展 订单信息组成该字符串
/**
* 订单详情扩展 订单信息组成该字符串
*/
@XStreamAlias("Package")
@JSONField(name = "package")
private String packageInfo;

View File

@ -1,7 +1,54 @@
支付模块【JSAPI】【NATIVE】
支付模块【JSAPI】【NATIVE】【MICROPAY】
微信公众平台[V2版本支付](https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course2_tmpl&lang=zh_CN)文档
微信公众平台[V3版本支付](https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course3_tmpl&lang=zh_CN)文档
**在`2014年10月9号`之前申请并审核通过的支付接口应该属于`V2版本`支付,而之后申请的接口则为`V3版本`支付**
**在`2014年10月9号`之前申请并审核通过的支付接口应该属于`V2版本`支付,而之后申请的接口则为`V3版本`支付**
[PayUtil](./PayUtil.java)
-------------------------
* createPayJsRequestJson: 创建JSAPI支付串
* createPayJsRequestJsonV2: 创建V2版本的JSAPI支付串
* createNativePayRequestURLV2: 创建V2版本的扫码支付链接
* createPayJsRequestJsonV3: 创建V3版本(商户平台)的JSAPI支付串
* createNativePayRequestURLV3: 创建V3版本(商户平台)的扫码支付链接
* createPrePay: 调用V3版本(商户平台)的统一订单接口生成预订单数据
* createMicroPay: 创建刷卡支付(商户平台)请求
* createAddressRequestJson: 生成编辑收货地址请求串
[Pay3Api](./Pay3Api.java)
-------------------------
* orderQuery: 订单查询接口
* refund: 退款申请接口
* reverse: 冲正订单接口
* closeOrder: 关闭订单接口
* downloadbill: 下载对账单接口
* refundQuery: 退款查询接口
[Pay2Api](./Pay2Api.java)
-------------------------
* orderQuery: 订单查询接口
* refund: 退款申请接口
* downloadbill: 下载对账单接口
* refundQuery: 退款查询接口

View File

@ -0,0 +1,371 @@
package com.foxinmy.weixin4j.mp.payment.coupon;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.mp.payment.v3.ApiResult;
import com.foxinmy.weixin4j.mp.type.CouponStatus;
import com.foxinmy.weixin4j.mp.type.CouponStockType;
import com.foxinmy.weixin4j.mp.type.CouponType;
import com.foxinmy.weixin4j.util.DateUtil;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 代金券详细
*
* @className CouponDetail
* @author jy
* @date 2015年3月27日
* @since JDK 1.7
* @see
*/
public class CouponDetail extends ApiResult {
private static final long serialVersionUID = -311265355895457070L;
/**
* 代金券批次Id
*/
@XStreamAlias("coupon_stock_id")
@JSONField(name = "coupon_stock_id")
private String couponStockId;
/**
* 批次类型1-批量型2-触发型
*/
@XStreamAlias("coupon_stock_type")
@JSONField(name = "coupon_stock_type")
private int couponStockType;
/**
* 代金券id
*/
@XStreamAlias("coupon_id")
@JSONField(name = "coupon_id")
private String couponId;
/**
* 代金券面值,单位是分
*/
@XStreamAlias("coupon_value")
@JSONField(name = "coupon_value")
private int couponValue;
/**
* 代金券使用最低限额,单位是分
*/
@XStreamAlias("coupon_mininum")
@JSONField(name = "coupon_mininum")
private int couponMininum;
/**
* 代金券名称
*/
@XStreamAlias("coupon_name")
@JSONField(name = "coupon_name")
private String couponName;
/**
* 代金券状态2-已激活4-已锁定8-已实扣
*/
@XStreamAlias("coupon_state")
@JSONField(name = "coupon_state")
private int couponStatus;
/**
* 代金券类型1-代金券无门槛2-代金券有门槛互斥3-代金券有门槛叠加
*/
@XStreamAlias("coupon_type")
@JSONField(name = "coupon_type")
private int couponType;
/**
* 代金券描述
*/
@XStreamAlias("coupon_desc")
@JSONField(name = "coupon_desc")
private String couponDesc;
/**
* 代金券实际使用金额
*/
@XStreamAlias("coupon_use_value")
@JSONField(name = "coupon_use_value")
private int couponUseValue;
/**
* 代金券剩余金额部分使用情况下可能会存在券剩余金额
*/
@XStreamAlias("coupon_remain_value")
@JSONField(name = "coupon_remain_value")
private int couponRemainValue;
/**
* 生效开始时间:格式为yyyyMMddhhmmss如2009年12月27日9点10分10秒表示为20091227091010
*/
@XStreamAlias("begin_time")
@JSONField(name = "begin_time")
private String beginTime;
/**
* 生效结束时间:格式为yyyyMMddhhmmss如2009年12月27日9点10分10秒表示为20091227091010
*/
@XStreamAlias("end_time")
@JSONField(name = "end_time")
private String endTime;
/**
* 发放时间:格式为yyyyMMddhhmmss如2009年12月27日9点10分10秒表示为20091227091010
*/
@XStreamAlias("send_time")
@JSONField(name = "send_time")
private String sendTime;
/**
* 使用时间:格式为yyyyMMddhhmmss如2009年12月27日9点10分10秒表示为20091227091010
*/
@XStreamAlias("use_time")
@JSONField(name = "use_time")
private String useTime;
/**
* 使用单号:代金券使用后关联的大单收单单号
*/
@XStreamAlias("trade_no")
@JSONField(name = "trade_no")
private String tradeNo;
/**
* 消耗方商户id:代金券使用后消耗方商户id
*/
@XStreamAlias("consumer_mch_id")
@JSONField(name = "consumer_mch_id")
private String consumerMchId;
/**
* 消耗方商户名称:代金券使用后消耗方商户名称
*/
@XStreamAlias("consumer_mch_name")
@JSONField(name = "consumer_mch_name")
private String consumerMchName;
/**
* 消耗方商户appid:代金券使用后消耗方商户appid
*/
@XStreamAlias("consumer_mch_appid")
@JSONField(name = "consumer_mch_appid")
private String consumerMchAppid;
/**
* 发放来源:代金券发放来源
*/
@XStreamAlias("send_source")
@JSONField(name = "send_source")
private String sendSource;
/**
* 是否允许部分使用:该代金券是否允许部分使用标识1-表示支持部分使用
*/
@XStreamAlias("is_partial_use")
@JSONField(name = "is_partial_use")
private int isPartialUse;
public String getCouponStockId() {
return couponStockId;
}
public int getCouponStockType() {
return couponStockType;
}
@JSONField(deserialize = false, serialize = false)
public CouponStockType getFormatCouponStockType() {
for (CouponStockType couponStockType : CouponStockType.values()) {
if (couponStockType.getVal() == this.couponStockType) {
return couponStockType;
}
}
return null;
}
public String getCouponId() {
return couponId;
}
public int getCouponValue() {
return couponValue;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(deserialize = false, serialize = false)
public double getFormatCouponValue() {
return couponValue / 100d;
}
public int getCouponMininum() {
return couponMininum;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(deserialize = false, serialize = false)
public double getFormatCouponMininum() {
return couponMininum / 100d;
}
public String getCouponName() {
return couponName;
}
public int getCouponStatus() {
return couponStatus;
}
@JSONField(deserialize = false, serialize = false)
public CouponStatus getFormatCouponStatus() {
for (CouponStatus couponStatus : CouponStatus.values()) {
if (couponStatus.getVal() == this.couponStatus) {
return couponStatus;
}
}
return null;
}
public int getCouponType() {
return couponType;
}
@JSONField(deserialize = false, serialize = false)
public CouponType getFormatCouponType() {
for (CouponType couponType : CouponType.values()) {
if (couponType.getVal() == this.couponType) {
return couponType;
}
}
return null;
}
public String getCouponDesc() {
return couponDesc;
}
public int getCouponUseValue() {
return couponUseValue;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(deserialize = false, serialize = false)
public double getFormatCouponUseValue() {
return couponUseValue / 100d;
}
public int getCouponRemainValue() {
return couponRemainValue;
}
/**
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
*
* @return 元单位
*/
@JSONField(deserialize = false, serialize = false)
public double getFormatCouponRemainValue() {
return couponRemainValue / 100d;
}
public String getBeginTime() {
return beginTime;
}
@JSONField(deserialize = false, serialize = false)
public Date getFormatBeginTime() {
return DateUtil.parse2yyyyMMddHHmmss(beginTime);
}
public String getEndTime() {
return endTime;
}
@JSONField(deserialize = false, serialize = false)
public Date getFormatEndTime() {
return DateUtil.parse2yyyyMMddHHmmss(endTime);
}
public String getSendTime() {
return sendTime;
}
@JSONField(deserialize = false, serialize = false)
public Date getFormatSendTime() {
return DateUtil.parse2yyyyMMddHHmmss(sendTime);
}
public String getUseTime() {
return useTime;
}
@JSONField(deserialize = false, serialize = false)
public Date getFormatUseTime() {
return StringUtils.isNotBlank(useTime) ? DateUtil
.parse2yyyyMMddHHmmss(useTime) : null;
}
public String getTradeNo() {
return tradeNo;
}
public String getConsumerMchId() {
return consumerMchId;
}
public String getConsumerMchName() {
return consumerMchName;
}
public String getConsumerMchAppid() {
return consumerMchAppid;
}
public String getSendSource() {
return sendSource;
}
public int getIsPartialUse() {
return isPartialUse;
}
@JSONField(deserialize = false, serialize = false)
public boolean getFormatIsPartialUse() {
return isPartialUse == 1;
}
@Override
public String toString() {
return "CouponDetail [couponStockId=" + couponStockId
+ ", couponStockType=" + getFormatCouponStockType()
+ ", couponId=" + couponId + ", couponValue="
+ getFormatCouponValue() + ", couponMininum="
+ getFormatCouponMininum() + ", couponName=" + couponName
+ ", couponStatus=" + getCouponStatus() + ", couponType="
+ getFormatCouponType() + ", couponDesc=" + couponDesc
+ ", couponUseValue=" + getFormatCouponUseValue()
+ ", couponRemainValue=" + getFormatCouponRemainValue()
+ ", beginTime=" + getFormatBeginTime() + ", endTime="
+ getFormatEndTime() + ", sendTime=" + getFormatSendTime()
+ ", useTime=" + getFormatUseTime() + ", tradeNo=" + tradeNo
+ ", consumerMchId=" + consumerMchId + ", consumerMchName="
+ consumerMchName + ", consumerMchAppid=" + consumerMchAppid
+ ", sendSource=" + sendSource + ", isPartialUse="
+ getFormatIsPartialUse() + ", " + super.toString()
+ "]";
}
}

Some files were not shown because too many files have changed in this diff Show More