diff --git a/CHANGE.md b/CHANGE.md index 389965d0..2776d2c7 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -210,7 +210,14 @@ + **weixin4j-mp**: 单行注释调整为多行文档注释 - + **weixin4j-mp**: 新增(CouponApi)[./weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/CouponApi.java]代金券接口 + + **weixin4j-mp**: 新增[CouponApi](./weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/CouponApi.java)代金券接口 + **weixin4j-qy**: 单行注释调整为多行文档注释 - \ No newline at end of file + +* 2015-04-01 + + + **weixin4j-mp**: 新增[CashApi](./weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/CashApi.java)发红包、企业付款接口 + + + **weixin4j-qy**: 新增[BatchApi](./weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/BatchApi.java)批量异步执行任务接口 + + + **weixin4j-qy**: DepartApi命名为[PartyApi](./weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/PartyApi.java) \ No newline at end of file diff --git a/README.md b/README.md index b2f73d61..8208d04a 100644 --- a/README.md +++ b/README.md @@ -71,10 +71,6 @@ netty的代码没有放到maven中心仓库,也没什么意义,因为最终需 接下来 ------ -* 企业号异步接口 - -* 红包和企业付款接口 - * 公众号服务应用 * 企业号第三方应用 diff --git a/weixin4j-base/README.md b/weixin4j-base/README.md index 176fbc37..76732a38 100644 --- a/weixin4j-base/README.md +++ b/weixin4j-base/README.md @@ -51,4 +51,8 @@ weixin4j-base * 2015-03-29 - + 单行注释调整为多行文档注释 \ No newline at end of file + + 单行注释调整为多行文档注释 + +* 2015-04-01 + + + 新增异步消息事件BatchjobresultMessage(./src/main/java/com/foxinmy/weixin4j/msg/event/BatchjobresultMessage.java) \ No newline at end of file diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/BatchjobresultMessage.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/BatchjobresultMessage.java new file mode 100644 index 00000000..509106bb --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/msg/event/BatchjobresultMessage.java @@ -0,0 +1,99 @@ +package com.foxinmy.weixin4j.msg.event; + +import java.io.Serializable; + +import com.foxinmy.weixin4j.type.EventType; +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + * 异步任务事件完成通知 + * + * @className BatchjobresultMessage + * @author jy + * @date 2015年3月31日 + * @since JDK 1.7 + * @see 异步任务事件完成通知 + */ +public class BatchjobresultMessage extends EventMessage { + + private static final long serialVersionUID = 8014540441322209657L; + + public BatchjobresultMessage() { + super(EventType.batch_job_result); + } + + /** + * 任务信息 + */ + @XStreamAlias("BatchJob") + private BatchJob batchJob; + + public BatchJob getBatchJob() { + return batchJob; + } + + /** + * 任务信息 + * + * @className BatchJob + * @author jy + * @date 2015年4月1日 + * @since JDK 1.7 + * @see + */ + public static class BatchJob implements Serializable { + private static final long serialVersionUID = -7520032656787156391L; + /** + * 异步任务id,最大长度为64字符 + */ + @XStreamAlias("JobId") + private String jobId; + /** + * 操作类型,字符串,目前分别有: 1. sync_user(增量更新成员) 2. replace_user(全量覆盖成员) 3. + * invite_user(邀请成员关注) 4. replace_party(全量覆盖部门) + * + * @see com.foxinmy.weixin4j.qy.type.BatchType + */ + @XStreamAlias("JobType") + private String jobType; + /** + * 返回码 + */ + @XStreamAlias("ErrCode") + private String ErrCode; + /** + * 对返回码的文本描述内容 + */ + @XStreamAlias("ErrMsg") + private String errMsg; + + public String getJobId() { + return jobId; + } + + public String getJobType() { + return jobType; + } + + public String getErrCode() { + return ErrCode; + } + + public String getErrMsg() { + return errMsg; + } + + @Override + public String toString() { + return "[jobId=" + jobId + ", jobType=" + jobType + ", ErrCode=" + + ErrCode + ", errMsg=" + errMsg + "]"; + } + } + + @Override + public String toString() { + return "BatchjobresultMessage [batchJob=" + batchJob + ", " + + super.toString() + "]"; + } +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/EventType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/EventType.java index b81d512d..5c563cd5 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/EventType.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/EventType.java @@ -1,5 +1,6 @@ package com.foxinmy.weixin4j.type; +import com.foxinmy.weixin4j.msg.event.BatchjobresultMessage; import com.foxinmy.weixin4j.msg.event.EnterAgentEventMessage; import com.foxinmy.weixin4j.msg.event.EventMessage; import com.foxinmy.weixin4j.msg.event.KfCloseEventMessage; @@ -132,7 +133,13 @@ public enum EventType { * * @see com.foxinmy.weixin4j.msg.event.KfSwitchEventMessage */ - kf_switch_session(KfSwitchEventMessage.class); + kf_switch_session(KfSwitchEventMessage.class), + /** + * 异步任务完成事件 + * + * @see com.foxinmy.weixin4j.msg.event.BatchjobresultMessage + */ + batch_job_result(BatchjobresultMessage.class); private Class eventClass; diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/xml/Map2ObjectConverter.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/xml/Map2ObjectConverter.java index 3967d19b..7128ccdb 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/xml/Map2ObjectConverter.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/xml/Map2ObjectConverter.java @@ -46,7 +46,10 @@ public class Map2ObjectConverter extends MapConverter { MarshallingContext context) { Map map = (Map) source; for (Entry entry : map.entrySet()) { - String value = (String) entry.getValue(); + if (entry.getValue() == null) { + continue; + } + String value = entry.getValue().toString(); if (StringUtils.isBlank(value)) { continue; } @@ -54,6 +57,7 @@ public class Map2ObjectConverter extends MapConverter { .getKey().toString(), entry.getClass()); writer.setValue(value); writer.endNode(); + } } } diff --git a/weixin4j-mp/README.md b/weixin4j-mp/README.md index b35ea2ee..dfdd7e11 100644 --- a/weixin4j-mp/README.md +++ b/weixin4j-mp/README.md @@ -37,6 +37,8 @@ weixin4j-mp + DataApi `数据统计API` + OauthApi `oauth授权API` + + + CashApi `现金API` * **weixin4j-mp-server** @@ -204,4 +206,8 @@ weixin4j-mp + **weixin4j-mp-api**: 单行注释调整为多行文档注释 - + **weixin4j-mp-api**: 新增(CouponApi)[./weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/CouponApi.java]代金券接口 \ No newline at end of file + + **weixin4j-mp-api**: 新增[CouponApi](./weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/CouponApi.java)代金券接口 + +* 2015-04-01 + + + **weixin4j-mp-api**: 新增[CashApi](./src/main/java/com/foxinmy/weixin4j/mp/api/CashApi.java)发红包、企业付款接口 \ No newline at end of file diff --git a/weixin4j-mp/weixin4j-mp-api/README.md b/weixin4j-mp/weixin4j-mp-api/README.md index 493e91c4..06500f2d 100644 --- a/weixin4j-mp/weixin4j-mp-api/README.md +++ b/weixin4j-mp/weixin4j-mp-api/README.md @@ -37,6 +37,8 @@ weixin4j-mp-api * OauthApi `oauth授权API` +* CashApi `现金API` + 如何使用 -------- 1.API工程可以单独打包到其他项目中使用,需新增或拷贝`weixin.properties`文件到项目的`classpath`中 @@ -179,4 +181,8 @@ weixin.properties说明 + 单行注释调整为多行文档注释 - + 新增(CouponApi)[./src/main/java/com/foxinmy/weixin4j/mp/api/CouponApi.java]代金券接口 \ No newline at end of file + + 新增[CouponApi](./src/main/java/com/foxinmy/weixin4j/mp/api/CouponApi.java)代金券接口 + +* 2015-04-01 + + + 新增[CashApi](./src/main/java/com/foxinmy/weixin4j/mp/api/CashApi.java)发红包、企业付款接口 \ No newline at end of file diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/WeixinPayProxy.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/WeixinPayProxy.java index 96b8bad6..45b9b635 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/WeixinPayProxy.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/WeixinPayProxy.java @@ -7,6 +7,7 @@ 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.CashApi; import com.foxinmy.weixin4j.mp.api.CouponApi; import com.foxinmy.weixin4j.mp.api.Pay2Api; import com.foxinmy.weixin4j.mp.api.Pay3Api; @@ -15,6 +16,10 @@ 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.payment.v3.MPPayment; +import com.foxinmy.weixin4j.mp.payment.v3.MPPaymentResult; +import com.foxinmy.weixin4j.mp.payment.v3.Redpacket; +import com.foxinmy.weixin4j.mp.payment.v3.RedpacketSendResult; import com.foxinmy.weixin4j.mp.type.BillType; import com.foxinmy.weixin4j.mp.type.CurrencyType; import com.foxinmy.weixin4j.mp.type.IdQuery; @@ -43,6 +48,7 @@ public class WeixinPayProxy { private final Pay2Api pay2Api; private final Pay3Api pay3Api; private final CouponApi couponApi; + private final CashApi cashApi; public WeixinPayProxy() { this(ConfigUtil.getWeixinMpAccount(), new FileTokenHolder( @@ -67,6 +73,7 @@ public class WeixinPayProxy { this.payApi = this.pay3Api; } this.couponApi = new CouponApi(weixinAccount); + this.cashApi = new CashApi(weixinAccount); } /** @@ -551,4 +558,66 @@ public class WeixinPayProxy { throws WeixinException { return couponApi.queryCouponDetail(couponId); } + + /** + * 发放红包 企业向微信用户个人发现金红包 + * + * @param caFile + * 证书文件(V3版本后缀为*.p12) + * @param redpacket + * 红包信息 + * @return 发放结果 + * @see com.foxinmy.weixin4j.mp.api.CashApi + * @see com.foxinmy.weixin4j.mp.payment.v3.Redpacket + * @see com.foxinmy.weixin4j.mp.payment.v3.RedpacketSendResult + * @see 红包接口说明 + * @throws WeixinException + */ + public RedpacketSendResult sendRedpack(File caFile, Redpacket redpacket) + throws WeixinException { + return cashApi.sendRedpack(caFile, redpacket); + } + + /** + * 发放红包采用properties中配置的ca文件 + * + * @see {@link com.foxinmy.weixin4j.mp.WeixinPayProxy#sendRedpack(File, Redpacket)} + */ + public RedpacketSendResult sendRedpack(Redpacket redpacket) + throws WeixinException { + File caFile = new File(ConfigUtil.getClassPathValue("ca_file")); + return cashApi.sendRedpack(caFile, redpacket); + } + + /** + * 企业付款 实现企业向个人付款,针对部分有开发能力的商户, 提供通过API完成企业付款的功能。 比如目前的保险行业向客户退保、给付、理赔。 + * + * @param caFile + * 证书文件(V3版本后缀为*.p12) + * @param mpPayment + * 付款信息 + * @return 付款结果 + * @see com.foxinmy.weixin4j.mp.api.CashApi + * @see com.foxinmy.weixin4j.mp.payment.v3.MPPayment + * @see com.foxinmy.weixin4j.mp.payment.v3.MPPaymentResult + * @see 企业付款 + * @throws WeixinException + */ + public MPPaymentResult mpPayment(File caFile, MPPayment mpPayment) + throws WeixinException { + return cashApi.mpPayment(caFile, mpPayment); + } + + /** + * 企业付款采用properties中配置的ca文件 + * + * @see {@link com.foxinmy.weixin4j.mp.WeixinPayProxy#mpPayment(File, MPPayment)} + */ + public MPPaymentResult mpPayment(MPPayment mpPayment) + throws WeixinException { + File caFile = new File(ConfigUtil.getClassPathValue("ca_file")); + return cashApi.mpPayment(caFile, mpPayment); + } } diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/CashApi.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/CashApi.java new file mode 100644 index 00000000..7f68afb7 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/CashApi.java @@ -0,0 +1,141 @@ +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 com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +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.v3.MPPayment; +import com.foxinmy.weixin4j.mp.payment.v3.MPPaymentResult; +import com.foxinmy.weixin4j.mp.payment.v3.Redpacket; +import com.foxinmy.weixin4j.mp.payment.v3.RedpacketSendResult; +import com.foxinmy.weixin4j.util.RandomUtil; + +/** + * 现金API + * + * @className CashApi + * @author jy + * @date 2015年3月28日 + * @since JDK 1.7 + * @see 现金红包 + * @see 企业付款 + */ +public class CashApi extends MpApi { + + private final WeixinMpAccount weixinAccount; + + public CashApi(WeixinMpAccount weixinAccount) { + this.weixinAccount = weixinAccount; + } + + /** + * 发放红包 企业向微信用户个人发现金红包 + * + * @param caFile + * 证书文件(V3版本后缀为*.p12) + * @param redpacket + * 红包信息 + * @return 发放结果 + * @see com.foxinmy.weixin4j.mp.payment.v3.Redpacket + * @see com.foxinmy.weixin4j.mp.payment.v3.RedpacketSendResult + * @see 红包接口说明 + * @throws WeixinException + */ + public RedpacketSendResult sendRedpack(File caFile, Redpacket redpacket) + throws WeixinException { + JSONObject obj = (JSONObject) JSON.toJSON(redpacket); + obj.put("nonce_str", RandomUtil.generateString(16)); + obj.put("mch_id", weixinAccount.getMchId()); + obj.put("sub_mch_id", weixinAccount.getSubMchId()); + obj.put("wxappid", weixinAccount.getId()); + String sign = PayUtil.paysignMd5(obj, weixinAccount.getPaySignKey()); + obj.put("sign", sign); + String param = map2xml(new HashMap(obj)); + String redpack_send_uri = getRequestUri("redpack_send_uri"); + Response response = null; + InputStream ca = null; + try { + ca = new FileInputStream(caFile); + SSLHttpRequest request = new SSLHttpRequest( + weixinAccount.getMchId(), ca); + response = request.post(redpack_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() { + }); + } + + /** + * 企业付款 实现企业向个人付款,针对部分有开发能力的商户, 提供通过API完成企业付款的功能。 比如目前的保险行业向客户退保、给付、理赔。 + * + * @param caFile + * 证书文件(V3版本后缀为*.p12) + * @param mpPayment + * 付款信息 + * @return 付款结果 + * @see com.foxinmy.weixin4j.mp.payment.v3.MPPayment + * @see com.foxinmy.weixin4j.mp.payment.v3.MPPaymentResult + * @see 企业付款 + * @throws WeixinException + */ + public MPPaymentResult mpPayment(File caFile, MPPayment mpPayment) + throws WeixinException { + JSONObject obj = (JSONObject) JSON.toJSON(mpPayment); + obj.put("nonce_str", RandomUtil.generateString(16)); + obj.put("mchid", weixinAccount.getMchId()); + obj.put("sub_mch_id", weixinAccount.getSubMchId()); + obj.put("mch_appid", weixinAccount.getId()); + obj.put("device_info", weixinAccount.getDeviceInfo()); + String sign = PayUtil.paysignMd5(obj, weixinAccount.getPaySignKey()); + obj.put("sign", sign); + String param = map2xml(new HashMap(obj)); + String mp_payment_uri = getRequestUri("mp_payment_uri"); + Response response = null; + InputStream ca = null; + try { + ca = new FileInputStream(caFile); + SSLHttpRequest request = new SSLHttpRequest( + weixinAccount.getMchId(), ca); + response = request.post(mp_payment_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() { + }); + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/Pay3Api.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/Pay3Api.java index d66e060b..59cf9a92 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/Pay3Api.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/Pay3Api.java @@ -53,7 +53,7 @@ import com.foxinmy.weixin4j.util.RandomUtil; * @author jy * @date 2014年10月28日 * @since JDK 1.7 - * @see 公众号支付API + * @see 商户平台API */ public class Pay3Api extends PayApi { diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties index 36d2dbd0..82f6f035 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties @@ -167,5 +167,7 @@ coupon_send_uri={mch_base_url}/mmpaymkttransfers/send_coupon 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 \ No newline at end of file +# \u53d1\u653e\u73b0\u91d1\u7ea2\u5305 +redpack_send_uri={mch_base_url}/mmpaymkttransfers/sendredpack +# \u4f01\u4e1a\u5411\u4e2a\u4eba\u4ed8\u6b3e +mp_payment_uri={mch_base_url}/mmpaymkttransfers/promotion/transfers \ No newline at end of file diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/MicroPayPackage.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/MicroPayPackage.java index cb78ccd3..d7071baa 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/MicroPayPackage.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/MicroPayPackage.java @@ -53,10 +53,6 @@ public class MicroPayPackage extends PayPackage { @JSONField(name = "auth_code") private String authCode; - public MicroPayPackage() { - - } - public MicroPayPackage(WeixinMpAccount weixinAccount, String body, String attach, String outTradeNo, double totalFee, String spbillCreateIp, String authCode) { @@ -83,34 +79,18 @@ public class MicroPayPackage extends PayPackage { return appid; } - public void setAppid(String appid) { - this.appid = appid; - } - public String getMchId() { return mchId; } - public void setMchId(String mchId) { - this.mchId = mchId; - } - public String getDeviceInfo() { return deviceInfo; } - public void setDeviceInfo(String deviceInfo) { - this.deviceInfo = deviceInfo; - } - public String getNonceStr() { return nonceStr; } - public void setNonceStr(String nonceStr) { - this.nonceStr = nonceStr; - } - public String getSign() { return sign; } diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v2/PayPackageV2.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v2/PayPackageV2.java index 3d554983..896aaf40 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v2/PayPackageV2.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v2/PayPackageV2.java @@ -55,12 +55,41 @@ public class PayPackageV2 extends PayPackage { @JSONField(name = "input_charset") private String inputCharset; - public String getBankType() { - return bankType; + public PayPackageV2(String outTradeNo, double totalFee, + String spbillCreateIp) { + this(null, null, null, outTradeNo, totalFee, null, spbillCreateIp, + null, null, 0d, 0d, null); } - public void setBankType(String bankType) { - this.bankType = bankType; + public PayPackageV2(String body, String outTradeNo, double totalFee, + String notifyUrl, String spbillCreateIp) { + this(body, null, null, outTradeNo, totalFee, notifyUrl, spbillCreateIp, + null, null, 0d, 0d, null); + } + + public PayPackageV2(String body, String partner, String outTradeNo, + double totalFee, String notifyUrl, String spbillCreateIp) { + this(body, null, partner, outTradeNo, totalFee, notifyUrl, + spbillCreateIp, null, null, 0d, 0d, null); + } + + public PayPackageV2(String body, String attach, String partner, + String outTradeNo, double totalFee, String notifyUrl, + String spbillCreateIp, Date timeStart, Date timeExpire, + double transportFee, double productFee, String goodsTag) { + super(body, attach, outTradeNo, totalFee, spbillCreateIp, timeStart, + timeExpire, goodsTag, notifyUrl); + this.bankType = "WX"; + this.feeType = "1"; + this.inputCharset = "UTF-8"; + this.transportFee = transportFee > 0d ? DateUtil + .formaFee2Fen(transportFee) : null; + this.productFee = productFee > 0 ? DateUtil.formaFee2Fen(productFee) + : null; + } + + public String getBankType() { + return bankType; } public String getPartner() { @@ -75,10 +104,6 @@ public class PayPackageV2 extends PayPackage { return feeType; } - public void setFeeType(String feeType) { - this.feeType = feeType; - } - public String getTransportFee() { return transportFee; } @@ -111,49 +136,6 @@ public class PayPackageV2 extends PayPackage { return inputCharset; } - public void setInputCharset(String inputCharset) { - this.inputCharset = inputCharset; - } - - public PayPackageV2() { - this.bankType = "WX"; - this.feeType = "1"; - this.inputCharset = "UTF-8"; - } - - public PayPackageV2(String outTradeNo, double totalFee, - String spbillCreateIp) { - this(null, null, null, outTradeNo, totalFee, null, spbillCreateIp, - null, null, 0d, 0d, null); - } - - public PayPackageV2(String body, String outTradeNo, double totalFee, - String notifyUrl, String spbillCreateIp) { - this(body, null, null, outTradeNo, totalFee, notifyUrl, spbillCreateIp, - null, null, 0d, 0d, null); - } - - public PayPackageV2(String body, String partner, String outTradeNo, - double totalFee, String notifyUrl, String spbillCreateIp) { - this(body, null, partner, outTradeNo, totalFee, notifyUrl, - spbillCreateIp, null, null, 0d, 0d, null); - } - - public PayPackageV2(String body, String attach, String partner, - String outTradeNo, double totalFee, String notifyUrl, - String spbillCreateIp, Date timeStart, Date timeExpire, - double transportFee, double productFee, String goodsTag) { - super(body, attach, outTradeNo, totalFee, spbillCreateIp, timeStart, - timeExpire, goodsTag, notifyUrl); - this.bankType = "WX"; - this.feeType = "1"; - this.inputCharset = "UTF-8"; - this.transportFee = transportFee > 0d ? DateUtil - .formaFee2Fen(transportFee) : null; - this.productFee = productFee > 0 ? DateUtil.formaFee2Fen(productFee) - : null; - } - @Override public String toString() { return "PayPackageV2 [bankType=" + bankType + ", partner=" + partner diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/MPPayment.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/MPPayment.java new file mode 100644 index 00000000..0d075db3 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/MPPayment.java @@ -0,0 +1,120 @@ +package com.foxinmy.weixin4j.mp.payment.v3; + +import java.io.Serializable; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.mp.type.MPPaymentCheckNameType; +import com.foxinmy.weixin4j.util.DateUtil; +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + * 企业付款 + * + * @className MPPayment + * @author jy + * @date 2015年4月1日 + * @since JDK 1.7 + * @see + */ +public class MPPayment implements Serializable { + + private static final long serialVersionUID = 3734639674346425312L; + /** + * 商户订单号 + */ + @XStreamAlias("partner_trade_no") + @JSONField(name = "partner_trade_no") + private String outTradeNo; + /** + * 接收红包的用户的openid + */ + private String openid; + /** + * 校验用户姓名选项 + * + * @see com.foxinmy.weixin4j.mp.type.MPPaymentCheckNameType + */ + @XStreamAlias("check_name") + @JSONField(name = "check_name") + private MPPaymentCheckNameType checkNameType; + /** + * 收款用户真实姓名。 如果check_name设置为FORCE_CHECK或OPTION_CHECK,则必填用户真实姓名 可选 + */ + @XStreamAlias("re_user_name") + @JSONField(name = "re_user_name") + private String userName; + /** + * 企业付款描述信息 + */ + private String desc; + /** + * 付款金额 + */ + private String amount; + /** + * 调用接口的机器Ip地址 + */ + @XStreamAlias("spbill_create_ip") + @JSONField(name = "spbill_create_ip") + private String clientIp; + + /** + * 企业付款 + * @param outTradeNo 商户的订单号 + * @param openid 用户的openid + * @param checkNameType 校验用户姓名选项 + * @param desc 描述 + * @param amount 金额 + * @param clientIp 调用接口IP + */ + public MPPayment(String outTradeNo, String openid, + MPPaymentCheckNameType checkNameType, String desc, double amount, + String clientIp) { + this.outTradeNo = outTradeNo; + this.openid = openid; + this.checkNameType = checkNameType; + this.desc = desc; + this.amount = DateUtil.formaFee2Fen(amount); + this.clientIp = clientIp; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public String getOpenid() { + return openid; + } + + public MPPaymentCheckNameType getCheckNameType() { + return checkNameType; + } + + public String getUserName() { + return userName; + } + + public String getDesc() { + return desc; + } + + public String getAmount() { + return amount; + } + + public String getClientIp() { + return clientIp; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + @Override + public String toString() { + return "MPPayment [outTradeNo=" + outTradeNo + ", openid=" + openid + + ", checkNameType=" + checkNameType + ", userName=" + userName + + ", desc=" + desc + ", amount=" + amount + ", clientIp=" + + clientIp + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/MPPaymentResult.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/MPPaymentResult.java new file mode 100644 index 00000000..8def029a --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/MPPaymentResult.java @@ -0,0 +1,56 @@ +package com.foxinmy.weixin4j.mp.payment.v3; + +import com.alibaba.fastjson.annotation.JSONField; +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + * 企业付款结果 + * + * @className MPPaymentResult + * @author jy + * @date 2015年4月1日 + * @since JDK 1.7 + * @see + */ +public class MPPaymentResult extends ApiResult { + + private static final long serialVersionUID = 1110472826089211646L; + + /** + * 微信订单订单号 + */ + @JSONField(name = "payment_no") + @XStreamAlias("payment_no") + private String transactionId; + /** + * 商户订单号 + */ + @JSONField(name = "partner_trade_no") + @XStreamAlias("partner_trade_no") + private String outTradeNo; + /** + * 支付时间 + */ + @JSONField(name = "payment_time") + @XStreamAlias("payment_time") + private String paymentTime; + + public String getTransactionId() { + return transactionId; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public String getPaymentTime() { + return paymentTime; + } + + @Override + public String toString() { + return "MPPaymentResult [transactionId=" + transactionId + + ", outTradeNo=" + outTradeNo + ", paymentTime=" + paymentTime + + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/PayPackageV3.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/PayPackageV3.java index 14515730..67bd91f4 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/PayPackageV3.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/PayPackageV3.java @@ -10,7 +10,7 @@ import com.foxinmy.weixin4j.util.RandomUtil; import com.thoughtworks.xstream.annotations.XStreamAlias; /** - * V3支付的订单详情
注意: totalFee字段传入时单位为元,创建支付时会转换为分 + * V3支付的订单详情 * * @className PayPackageV3 * @author jy @@ -66,10 +66,6 @@ public class PayPackageV3 extends PayPackage { @JSONField(name = "product_id") private String productId; - public PayPackageV3() { - - } - public PayPackageV3(WeixinMpAccount weixinAccount, String openId, String body, String outTradeNo, double totalFee, String spbillCreateIp, TradeType tradeType) { @@ -106,34 +102,18 @@ public class PayPackageV3 extends PayPackage { return appid; } - public void setAppid(String appid) { - this.appid = appid; - } - public String getMchId() { return mchId; } - public void setMchId(String mchId) { - this.mchId = mchId; - } - public String getDeviceInfo() { return deviceInfo; } - public void setDeviceInfo(String deviceInfo) { - this.deviceInfo = deviceInfo; - } - public String getNonceStr() { return nonceStr; } - public void setNonceStr(String nonceStr) { - this.nonceStr = nonceStr; - } - public String getSign() { return sign; } @@ -146,18 +126,10 @@ public class PayPackageV3 extends PayPackage { return tradeType; } - public void setTradeType(TradeType tradeType) { - this.tradeType = tradeType.name(); - } - public String getOpenid() { return openid; } - public void setOpenid(String openid) { - this.openid = openid; - } - public String getProductId() { return productId; } diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/Redpacket.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/Redpacket.java new file mode 100644 index 00000000..5f416320 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/Redpacket.java @@ -0,0 +1,272 @@ +package com.foxinmy.weixin4j.mp.payment.v3; + +import java.io.Serializable; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.util.DateUtil; +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + * 红包 + * + * @className Redpacket + * @author jy + * @date 2015年3月28日 + * @since JDK 1.7 + * @see 红包简介 + */ +public class Redpacket implements Serializable { + + private static final long serialVersionUID = -7021352305575714281L; + /** + * 商户订单号(每个订单号必须唯一) 组成: mch_id+yyyymmdd+10位一天内不能重复的数字。 + */ + @XStreamAlias("mch_billno") + @JSONField(name = "mch_billno") + private String outTradeNo; + /** + * 提供方名称 必填 + */ + @XStreamAlias("nick_name") + @JSONField(name = "nick_name") + private String nickName; + /** + * 红包发送者名称 必填 + */ + @XStreamAlias("send_name") + @JSONField(name = "send_name") + private String sendName; + /** + * 接收红包的用户的openid + */ + @XStreamAlias("re_openid") + @JSONField(name = "re_openid") + private String openid; + /** + * 付款金额,单位分 + */ + @XStreamAlias("total_amount") + @JSONField(name = "total_amount") + private String totalAmount; + /** + * 最小红包金额,单位分 + */ + @XStreamAlias("min_value") + @JSONField(name = "min_value") + private String minValue; + /** + * 最大红包金额,单位分( 最小金额等于最大金额: min_value=max_value =total_amount) + */ + @XStreamAlias("max_value") + @JSONField(name = "max_value") + private String maxValue; + /** + * 红包发放总人数 + */ + @XStreamAlias("total_num") + @JSONField(name = "total_num") + private int totalNum; + /** + * 红包祝福语 + */ + private String wishing; + /** + * ip地址 + */ + @XStreamAlias("client_ip") + @JSONField(name = "client_ip") + private String clientIp; + /** + * 活动名称 + */ + @XStreamAlias("act_name") + @JSONField(name = "act_name") + private String actName; + /** + * 备注 + */ + private String remark; + /** + * 商户logo的url 非必填 + */ + @XStreamAlias("logo_imgurl") + @JSONField(name = "logo_imgurl") + private String logoUrl; + /** + * 分享文案 非必填 + */ + @XStreamAlias("share_content") + @JSONField(name = "share_content") + private String shareContent; + /** + * 分享链接 非必填 + */ + @XStreamAlias("share_url") + @JSONField(name = "share_url") + private String shareUrl; + /** + * 分享的图片 非必填 + */ + @XStreamAlias("share_imgurl") + @JSONField(name = "share_imgurl") + private String shareImageUrl; + + public String getOutTradeNo() { + return outTradeNo; + } + + public void setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getSendName() { + return sendName; + } + + public void setSendName(String sendName) { + this.sendName = sendName; + } + + public String getOpenid() { + return openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public String getTotalAmount() { + return totalAmount; + } + + /** + * 单位为元,自动格式化为分 + * + * @param totalAmount + * 付款金额 单位为元 + */ + public void setTotalAmount(double totalAmount) { + this.totalAmount = DateUtil.formaFee2Fen(totalAmount); + } + + public String getMinValue() { + return minValue; + } + + /** + * 单位为元,自动格式化为分 + * + * @param minValue + * 最小红包 单位为元 + */ + public void setMinValue(double minValue) { + this.minValue = DateUtil.formaFee2Fen(minValue); + } + + public String getMaxValue() { + return maxValue; + } + + /** + * 单位为元,自动格式化为分 + * + * @param minValue + * 最大红包 单位为元 + */ + public void setMaxValue(double maxValue) { + this.maxValue = DateUtil.formaFee2Fen(maxValue); + } + + public int getTotalNum() { + return totalNum; + } + + public void setTotalNum(int totalNum) { + this.totalNum = totalNum; + } + + public String getWishing() { + return wishing; + } + + public void setWishing(String wishing) { + this.wishing = wishing; + } + + public String getClientIp() { + return clientIp; + } + + public void setClientIp(String clientIp) { + this.clientIp = clientIp; + } + + public String getActName() { + return actName; + } + + public void setActName(String actName) { + this.actName = actName; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getLogoUrl() { + return logoUrl; + } + + public void setLogoUrl(String logoUrl) { + this.logoUrl = logoUrl; + } + + public String getShareContent() { + return shareContent; + } + + public void setShareContent(String shareContent) { + this.shareContent = shareContent; + } + + public String getShareUrl() { + return shareUrl; + } + + public void setShareUrl(String shareUrl) { + this.shareUrl = shareUrl; + } + + public String getShareImageUrl() { + return shareImageUrl; + } + + public void setShareImageUrl(String shareImageUrl) { + this.shareImageUrl = shareImageUrl; + } + + @Override + public String toString() { + return "Redpacket [ nickName=" + nickName + + ", sendName=" + sendName + ", openid=" + openid + + ", totalAmount=" + totalAmount + ", minValue=" + minValue + + ", maxValue=" + maxValue + ", totalNum=" + totalNum + + ", wishing=" + wishing + ", clientIp=" + clientIp + + ", actName=" + actName + ", remark=" + remark + ", logoUrl=" + + logoUrl + ", shareContent=" + shareContent + ", shareUrl=" + + shareUrl + ", shareImageUrl=" + shareImageUrl + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/RedpacketSendResult.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/RedpacketSendResult.java new file mode 100644 index 00000000..7e7db387 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/RedpacketSendResult.java @@ -0,0 +1,87 @@ +package com.foxinmy.weixin4j.mp.payment.v3; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.http.XmlResult; +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + * 发送红包结果 + * + * @className RedpacketSendResult + * @author jy + * @date 2015年4月1日 + * @since JDK 1.7 + * @see + */ +public class RedpacketSendResult extends XmlResult { + + private static final long serialVersionUID = 5611847899634131711L; + /** + * 微信分配的公众账号 + */ + @XStreamAlias("wxappid") + @JSONField(name = "wxappid") + private String appid; + /** + * 微信支付分配的商户号 + */ + @XStreamAlias("mch_id") + @JSONField(name = "mch_id") + private String mchId; + /** + * 商户订单号(每个订单号必须唯一) 组成: mch_id+yyyymmdd+10位一天内不能重复的数字。 + */ + @XStreamAlias("mch_billno") + @JSONField(name = "mch_billno") + private String outTradeNo; + /** + * 接收红包的用户的openid + */ + @XStreamAlias("re_openid") + @JSONField(name = "re_openid") + private String openid; + /** + * 付款金额 单位为分 + */ + @XStreamAlias("total_amount") + @JSONField(name = "total_amount") + private int totalAmount; + + public String getAppid() { + return appid; + } + + public String getMchId() { + return mchId; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public String getOpenid() { + return openid; + } + + public int getTotalAmount() { + return totalAmount; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false, deserialize = false) + public double getFormatTotalAmount() { + return totalAmount / 100d; + } + + @Override + public String toString() { + return "RedpacketSendResult [appid=" + appid + ", mchId=" + mchId + + ", outTradeNo=" + outTradeNo + ", openid=" + openid + + ", totalAmount=" + totalAmount + ", " + super.toString() + + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/MPPaymentCheckNameType.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/MPPaymentCheckNameType.java new file mode 100644 index 00000000..fba73c2b --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/type/MPPaymentCheckNameType.java @@ -0,0 +1,25 @@ +package com.foxinmy.weixin4j.mp.type; + +/** + * 企业付款检查收款人姓名的策略 + * + * @className MPPaymentCheckType + * @author jy + * @date 2015年4月1日 + * @since JDK 1.7 + * @see + */ +public enum MPPaymentCheckNameType { + /** + * 不校验真实姓名 + */ + NO_CHECK, + /** + * 强校验真实姓名(未实名认证的用户会校验失败,无法转账) + */ + FORCE_CHECK, + /** + * 针对已实名认证的用户才校验真实姓名(未实名认证用户不校验,可以转账成功) + */ + OPTION_CHECK; +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/CashTest.java b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/CashTest.java new file mode 100644 index 00000000..ccbcbcd4 --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/CashTest.java @@ -0,0 +1,50 @@ +package com.foxinmy.weixin4j.mp.test; + +import org.junit.Test; + +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.mp.payment.v3.MPPayment; +import com.foxinmy.weixin4j.mp.payment.v3.MPPaymentResult; +import com.foxinmy.weixin4j.mp.payment.v3.Redpacket; +import com.foxinmy.weixin4j.mp.payment.v3.RedpacketSendResult; +import com.foxinmy.weixin4j.mp.type.MPPaymentCheckNameType; + +/** + * 现金发放测试 + * + * @className CashTest + * @author jy + * @date 2015年4月1日 + * @since JDK 1.7 + * @see + */ +public class CashTest extends CouponTest { + + @Test + public void sendRedpacket() throws WeixinException { + Redpacket redpacket = new Redpacket(); + redpacket.setActName("红包测试"); + redpacket.setClientIp("127.0.0.1"); + redpacket.setMaxValue(1d); + redpacket.setMinValue(1d); + redpacket.setNickName("无忧钱庄"); + redpacket.setOpenid("oyFLst1bqtuTcxK-ojF8hOGtLQao"); + redpacket.setOutTradeNo("HB001"); + redpacket.setRemark("快来领取红包吧!"); + redpacket.setSendName("无忧钱庄"); + redpacket.setTotalAmount(1d); + redpacket.setTotalNum(1); + redpacket.setWishing("来就送钱"); + RedpacketSendResult result = WEIXINPAY.sendRedpack(caFile, redpacket); + System.err.println(result); + } + + @Test + public void mpPayment() throws WeixinException { + MPPayment payment = new MPPayment("MP001", + "oyFLst1bqtuTcxK-ojF8hOGtLQao", + MPPaymentCheckNameType.NO_CHECK, "企业付款测试", 0.01d, "127.0.0.1"); + MPPaymentResult result = WEIXINPAY.mpPayment(caFile, payment); + System.err.println(result); + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/CouponTest.java b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/CouponTest.java index 73e4d5ed..764a0890 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/CouponTest.java +++ b/weixin4j-mp/weixin4j-mp-api/src/test/java/com/foxinmy/weixin4j/mp/test/CouponTest.java @@ -28,18 +28,18 @@ import com.foxinmy.weixin4j.util.DateUtil; * @see */ public class CouponTest { - private final static WeixinPayProxy WEIXINPAY; - private final static WeixinMpAccount ACCOUNT; + protected final static WeixinPayProxy WEIXINPAY; + protected final static WeixinMpAccount ACCOUNT; static { - ACCOUNT = new WeixinMpAccount("wx0d1d598c0c03c999", - "2513ac683f1beabdb6b98d9ddd9e5755", - "GATFzDwbQdbbci3QEQxX2rUBvwTrsMiZ", "10020674"); + ACCOUNT = new WeixinMpAccount("公众号的id", + "公众号的secret", + "公众号的支付密钥", "商户平台的id"); WEIXINPAY = new WeixinPayProxy(ACCOUNT, new FileTokenHolder( new WeixinTokenCreator(ACCOUNT.getId(), ACCOUNT.getSecret(), AccountType.MP))); } - private final File caFile = new File( - "/Users/jy/workspace/feican/canyi-weixin-parent/canyi-weixin-service/src/main/resources/10020674.p12"); + protected final File caFile = new File( + "证书文件的路径(*.p12)"); @Test public void sendCoupon() throws WeixinException { diff --git a/weixin4j-qy/README.md b/weixin4j-qy/README.md index f752b7f5..487a228b 100644 --- a/weixin4j-qy/README.md +++ b/weixin4j-qy/README.md @@ -8,7 +8,7 @@ weixin4j-qy ------- * **weixin4j-qy-api** - + DepartApi `部门管理API` + + PartyApi `部门管理API` + UserApi `成员管理API` @@ -21,6 +21,8 @@ weixin4j-qy + NotifyApi `消息发送API` + AgentApi `应用设置API` + + + BatchApi `批量任务API` * **weixin4j-qy-server** @@ -122,3 +124,9 @@ weixin4j-qy * 2015-03-29 + **weixin4j-qy-api**: 单行注释调整为多行文档注释 + +* 2015-04-01 + + + **weixin4j-qy-api**: 新增[BatchApi](./weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/BatchApi.java)批量异步执行任务接口 + + + **weixin4j-qy-api**: DepartApi命名为[PartyApi](./weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/PartyApi.java) diff --git a/weixin4j-qy/weixin4j-qy-api/README.md b/weixin4j-qy/weixin4j-qy-api/README.md index c6816238..267d7d50 100644 --- a/weixin4j-qy/weixin4j-qy-api/README.md +++ b/weixin4j-qy/weixin4j-qy-api/README.md @@ -7,7 +7,7 @@ weixin4j-qy-api 功能列表 ------- - * DepartApi `部门管理API` + * PartyApi `部门管理API` * UserApi `成员管理API` @@ -93,3 +93,9 @@ weixin.properties说明 * 2015-03-29 + 单行注释调整为多行文档注释 + +* 2015-04-01 + + + 新增[BatchApi](./src/main/java/com/foxinmy/weixin4j/qy/api/BatchApi.java)批量异步执行任务接口 + + + DepartApi命名为[PartyApi](./src/main/java/com/foxinmy/weixin4j/qy/api/PartyApi.java) diff --git a/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java index 8534742a..b01bf957 100644 --- a/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java +++ b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java @@ -5,13 +5,17 @@ import java.util.List; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.qy.api.AgentApi; -import com.foxinmy.weixin4j.qy.api.DepartApi; +import com.foxinmy.weixin4j.qy.api.BatchApi; import com.foxinmy.weixin4j.qy.api.HelperApi; +import com.foxinmy.weixin4j.qy.api.PartyApi; import com.foxinmy.weixin4j.qy.api.TagApi; import com.foxinmy.weixin4j.qy.api.UserApi; import com.foxinmy.weixin4j.qy.model.AgentInfo; import com.foxinmy.weixin4j.qy.model.AgentSetter; -import com.foxinmy.weixin4j.qy.model.Department; +import com.foxinmy.weixin4j.qy.model.BatchResult; +import com.foxinmy.weixin4j.qy.model.Callback; +import com.foxinmy.weixin4j.qy.model.IdParameter; +import com.foxinmy.weixin4j.qy.model.Party; import com.foxinmy.weixin4j.qy.model.Tag; import com.foxinmy.weixin4j.qy.model.User; import com.foxinmy.weixin4j.qy.type.InviteType; @@ -31,11 +35,12 @@ import com.foxinmy.weixin4j.type.AccountType; * @see api文档 */ public class WeixinProxy { - private final DepartApi departApi; + private final PartyApi partyApi; private final UserApi userApi; private final TagApi tagApi; private final HelperApi helperApi; private final AgentApi agentApi; + private final BatchApi batchApi; /** * 默认采用文件存放Token信息 @@ -61,74 +66,75 @@ public class WeixinProxy { * @param tokenHolder */ public WeixinProxy(TokenHolder tokenHolder) { - this.departApi = new DepartApi(tokenHolder); + this.partyApi = new PartyApi(tokenHolder); this.userApi = new UserApi(tokenHolder); this.tagApi = new TagApi(tokenHolder); this.helperApi = new HelperApi(tokenHolder); this.agentApi = new AgentApi(tokenHolder); + this.batchApi = new BatchApi(tokenHolder); } /** * 创建部门(根部门的parentid为1) * - * @param depart + * @param party * 部门对象 - * @see com.foxinmy.weixin4j.qy.model.Department + * @see com.foxinmy.weixin4j.qy.model.Party * @see 创建部门说明 - * @see com.foxinmy.weixin4j.qy.api.DepartApi + * @see com.foxinmy.weixin4j.qy.api.PartyApi * @return 部门ID * @throws WeixinException */ - public int createDepart(Department depart) throws WeixinException { - return departApi.createDepart(depart); + public int createParty(Party party) throws WeixinException { + return partyApi.createParty(party); } /** * 更新部门(如果非必须的字段未指定 则不更新该字段之前的设置值) * - * @param depart + * @param party * 部门对象 - * @see com.foxinmy.weixin4j.qy.model.Department + * @see com.foxinmy.weixin4j.qy.model.Party * @see 更新部门说明 - * @see com.foxinmy.weixin4j.qy.api.DepartApi + * @see com.foxinmy.weixin4j.qy.api.PartyApi * @return 处理结果 * @throws WeixinException */ - public JsonResult updateDepart(Department depart) throws WeixinException { - return departApi.updateDepart(depart); + public JsonResult updateParty(Party party) throws WeixinException { + return partyApi.updateParty(party); } /** * 查询部门列表(以部门的order字段从小到大排列) * - * @param departId + * @param partyId * 部门ID。获取指定部门ID下的子部门 - * @see com.foxinmy.weixin4j.qy.model.Department + * @see com.foxinmy.weixin4j.qy.model.Party * @see 获取部门列表 - * @see com.foxinmy.weixin4j.qy.api.DepartApi + * @see com.foxinmy.weixin4j.qy.api.PartyApi * @return 部门列表 * @throws WeixinException */ - public List listDepart(int departId) throws WeixinException { - return departApi.listDepart(departId); + public List listParty(int partyId) throws WeixinException { + return partyApi.listParty(partyId); } /** * 删除部门(不能删除根部门;不能删除含有子部门、成员的部门) * - * @param departId + * @param partyId * 部门ID * @see 删除部门说明 - * @see com.foxinmy.weixin4j.qy.api.DepartApi + * @see com.foxinmy.weixin4j.qy.api.PartyApi * @return 处理结果 * @throws WeixinException */ - public JsonResult deleteDepart(int departId) throws WeixinException { - return departApi.deleteDepart(departId); + public JsonResult deleteParty(int partyId) throws WeixinException { + return partyApi.deleteParty(partyId); } /** @@ -202,7 +208,7 @@ public class WeixinProxy { /** * 获取部门成员 * - * @param departId + * @param partyId * 部门ID 必须 * @param fetchChild * 是否递归获取子部门下面的成员 非必须 @@ -217,9 +223,9 @@ public class WeixinProxy { * @return 成员列表 * @throws WeixinException */ - public List listUser(int departId, boolean fetchChild, + public List listUser(int partyId, boolean fetchChild, UserStatus userStatus, boolean findDetail) throws WeixinException { - return userApi.listUser(departId, fetchChild, userStatus, findDetail); + return userApi.listUser(partyId, fetchChild, userStatus, findDetail); } /** @@ -445,4 +451,114 @@ public class WeixinProxy { public JsonResult setAgent(AgentSetter agentSet) throws WeixinException { return agentApi.setAgent(agentSet); } + + /** + * 批量邀请成员关注 + * + * @param parameter + * 成员ID,标签ID,部门ID + * @param callback + * 接收任务执行结果的回调地址等信息 + * @param tips + * 推送到微信上的提示语(只有认证号可以使用)。当使用微信推送时,该字段默认为“请关注XXX企业号”,邮件邀请时,该字段无效。 + * @return 异步任务id,最大长度为64字符 + * @see com.foxinmy.weixin4j.qy.model.IdParameter + * @see com.foxinmy.weixin4j.qy.model.Callback + * @see com.foxinmy.weixin4j.qy.api.BatchApi + * @see 邀请成员关注 + * @throws WeixinException + */ + public String inviteuser(IdParameter parameter, Callback callback, + String tips) throws WeixinException { + return batchApi.inviteuser(parameter, callback, tips); + } + + /** + * 批量更新成员,本接口以userid为主键,增量更新企业号通讯录成员。 + *

+ * 1.模板中的部门需填写部门ID,多个部门用分号分隔,部门ID必须为数字
+ * 2.文件中存在、通讯录中也存在的成员,更新成员在文件中指定的字段值
3.文件中存在、通讯录中不存在的成员,执行添加操作
+ * 4.通讯录中存在、文件中不存在的成员,保持不变
+ *

+ * + * @param mediaId + * 带user信息的cvs文件上传后的media_id + * @param callback + * 接收任务执行结果的回调地址等信息 + * @return 异步任务id,最大长度为64字符 + * @see com.foxinmy.weixin4j.qy.model.Callback + * @see com.foxinmy.weixin4j.qy.api.BatchApi + * @see 批量更新成员 + * @throws WeixinException + */ + public String syncuser(String mediaId, Callback callback) + throws WeixinException { + return batchApi.syncuser(mediaId, callback); + } + + /** + * 批量覆盖成员,本接口以userid为主键,全量覆盖企业号通讯录成员,任务完成后企业号通讯录成员与提交的文件完全保持一致。 + *

+ * 1.模板中的部门需填写部门ID,多个部门用分号分隔,部门ID必须为数字
2.文件中存在、通讯录中也存在的成员,完全以文件为准
+ * 3.文件中存在、通讯录中不存在的成员,执行添加操作
+ * 4.通讯录中存在、文件中不存在的成员,执行删除操作。出于安全考虑,如果需要删除的成员多于50人, + * 且多于现有人数的20%以上,系统将中止导入并返回相应的错误码 + *

+ * + * @param mediaId + * 带userid信息的cvs文件上传后的media_id + * @param callback + * 接收任务执行结果的回调地址等信息 + * @return 异步任务id,最大长度为64字符 + * @see com.foxinmy.weixin4j.qy.model.Callback + * @see com.foxinmy.weixin4j.qy.api.BatchApi + * @see 批量覆盖成员 + * @throws WeixinException + */ + public String replaceuser(String mediaId, Callback callback) + throws WeixinException { + return batchApi.replaceuser(mediaId, callback); + } + /** + * 批量覆盖部门,本接口以partyid为键,全量覆盖企业号通讯录组织架构,任务完成后企业号通讯录组织架构与提交的文件完全保持一致。 + *

+ * 1.文件中存在、通讯录中也存在的部门,执行修改操作
2.文件中存在、通讯录中不存在的部门,执行添加操作
+ * 3.文件中不存在、通讯录中存在的部门,当部门为空时,执行删除操作
+ * 4.CSV文件中,部门名称、部门ID、父部门ID为必填字段,部门ID必须为数字;排序为可选字段,置空或填0不修改排序 + *

+ * + * @param mediaId + * 带partyid信息的cvs文件上传后的media_id + * @param callback + * 接收任务执行结果的回调地址等信息 + * @return 异步任务id,最大长度为64字符 + * @see com.foxinmy.weixin4j.qy.model.Callback + * @see com.foxinmy.weixin4j.qy.api.BatchApi + * @see 批量覆盖部门 + * @throws WeixinException + */ + public String replaceparty(String mediaId, Callback callback) + throws WeixinException { + return batchApi.replaceparty(mediaId, callback); + } + + /** + * 获取异步任务执行的结果 + * + * @param jobId + * 任务ID + * @return 效果信息 + * @see com.foxinmy.weixin4j.qy.model.BatchResult + * @see com.foxinmy.weixin4j.qy.api.BatchApi + * @see 获取异步任务执行结果 + * @throws WeixinException + */ + public BatchResult getresult(String jobId) throws WeixinException { + return batchApi.getresult(jobId); + } } diff --git a/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/BatchApi.java b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/BatchApi.java new file mode 100644 index 00000000..9dbd7cf2 --- /dev/null +++ b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/BatchApi.java @@ -0,0 +1,168 @@ +package com.foxinmy.weixin4j.qy.api; + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.Response; +import com.foxinmy.weixin4j.model.Token; +import com.foxinmy.weixin4j.qy.model.BatchResult; +import com.foxinmy.weixin4j.qy.model.Callback; +import com.foxinmy.weixin4j.qy.model.IdParameter; +import com.foxinmy.weixin4j.token.TokenHolder; + +/** + * 批量异步任务API + *

+ * 异步任务接口用于大批量数据的处理,提交后接口即返回,企业号会在后台继续执行任务。执行完成后,通过任务事件通知企业获取结果 + *

+ * + * @className BatchApi + * @author jy + * @date 2015年3月30日 + * @since JDK 1.7 + * @see 批量任务 + */ +public class BatchApi extends QyApi { + + private final TokenHolder tokenHolder; + + public BatchApi(TokenHolder tokenHolder) { + this.tokenHolder = tokenHolder; + } + + /** + * 批量邀请成员关注 + * + * @param parameter + * 成员ID,标签ID,部门ID + * @param callback + * 接收任务执行结果的回调地址等信息 + * @param tips + * 推送到微信上的提示语(只有认证号可以使用)。当使用微信推送时,该字段默认为“请关注XXX企业号”,邮件邀请时,该字段无效。 + * @return 异步任务id,最大长度为64字符 + * @see com.foxinmy.weixin4j.qy.model.IdParameter + * @see com.foxinmy.weixin4j.qy.model.Callback + * @see 邀请成员关注 + * @throws WeixinException + */ + public String inviteuser(IdParameter parameter, Callback callback, + String tips) throws WeixinException { + String batch_inviteuser_uri = getRequestUri("batch_inviteuser_uri"); + Token token = tokenHolder.getToken(); + JSONObject obj = new JSONObject(); + obj.putAll(parameter.getParameter()); + obj.put("callback", callback); + obj.put("invite_tips", tips); + Response response = request.post( + String.format(batch_inviteuser_uri, token.getAccessToken()), + obj.toJSONString()); + return response.getAsJson().getString("jobid"); + } + + /** + * 批量更新成员,本接口以userid为主键,增量更新企业号通讯录成员。 + *

+ * 1.模板中的部门需填写部门ID,多个部门用分号分隔,部门ID必须为数字
+ * 2.文件中存在、通讯录中也存在的成员,更新成员在文件中指定的字段值
3.文件中存在、通讯录中不存在的成员,执行添加操作
+ * 4.通讯录中存在、文件中不存在的成员,保持不变
+ *

+ * + * @param mediaId + * 带user信息的cvs文件上传后的media_id TODO + * @param callback + * 接收任务执行结果的回调地址等信息 + * @return 异步任务id,最大长度为64字符 + * @see com.foxinmy.weixin4j.qy.model.Callback + * @see 批量更新成员 + * @throws WeixinException + */ + public String syncuser(String mediaId, Callback callback) + throws WeixinException { + String batch_syncuser_uri = getRequestUri("batch_syncuser_uri"); + return batch(batch_syncuser_uri, mediaId, callback); + } + + private String batch(String batchUrl, String mediaId, Callback callback) + throws WeixinException { + Token token = tokenHolder.getToken(); + JSONObject obj = new JSONObject(); + obj.put("media_id", mediaId); + obj.put("callback", callback); + Response response = request.post( + String.format(batchUrl, token.getAccessToken()), + obj.toJSONString()); + return response.getAsJson().getString("jobid"); + } + + /** + * 批量覆盖成员,本接口以userid为主键,全量覆盖企业号通讯录成员,任务完成后企业号通讯录成员与提交的文件完全保持一致。 + *

+ * 1.模板中的部门需填写部门ID,多个部门用分号分隔,部门ID必须为数字
2.文件中存在、通讯录中也存在的成员,完全以文件为准
+ * 3.文件中存在、通讯录中不存在的成员,执行添加操作
+ * 4.通讯录中存在、文件中不存在的成员,执行删除操作。出于安全考虑,如果需要删除的成员多于50人, + * 且多于现有人数的20%以上,系统将中止导入并返回相应的错误码 + *

+ * + * @param mediaId + * 带userid信息的cvs文件上传后的media_id + * @param callback + * 接收任务执行结果的回调地址等信息 + * @return 异步任务id,最大长度为64字符 + * @see com.foxinmy.weixin4j.qy.model.Callback + * @see 批量覆盖成员 + * @throws WeixinException + */ + public String replaceuser(String mediaId, Callback callback) + throws WeixinException { + String batch_replaceuser_uri = getRequestUri("batch_replaceuser_uri"); + return batch(batch_replaceuser_uri, mediaId, callback); + } + + /** + * 批量覆盖部门,本接口以partyid为键,全量覆盖企业号通讯录组织架构,任务完成后企业号通讯录组织架构与提交的文件完全保持一致。 + *

+ * 1.文件中存在、通讯录中也存在的部门,执行修改操作
2.文件中存在、通讯录中不存在的部门,执行添加操作
+ * 3.文件中不存在、通讯录中存在的部门,当部门为空时,执行删除操作
+ * 4.CSV文件中,部门名称、部门ID、父部门ID为必填字段,部门ID必须为数字;排序为可选字段,置空或填0不修改排序 + *

+ * + * @param mediaId + * 带partyid信息的cvs文件上传后的media_id + * @param callback + * 接收任务执行结果的回调地址等信息 + * @return 异步任务id,最大长度为64字符 + * @see com.foxinmy.weixin4j.qy.model.Callback + * @see 批量覆盖部门 + * @throws WeixinException + */ + public String replaceparty(String mediaId, Callback callback) + throws WeixinException { + String batch_replaceparty_uri = getRequestUri("batch_replaceparty_uri"); + return batch(batch_replaceparty_uri, mediaId, callback); + } + + /** + * 获取异步任务执行的结果 + * + * @param jobId + * 任务ID + * @return 效果信息 + * @see com.foxinmy.weixin4j.qy.model.BatchResult + * @see 获取异步任务执行结果 + * @throws WeixinException + */ + public BatchResult getresult(String jobId) throws WeixinException { + Token token = tokenHolder.getToken(); + String batch_getresult_uri = getRequestUri("batch_getresult_uri"); + Response response = request.get(String.format(batch_getresult_uri, + token.getAccessToken(), jobId)); + return response.getAsObject(new TypeReference() { + }); + } +} diff --git a/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/DepartApi.java b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/PartyApi.java similarity index 79% rename from weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/DepartApi.java rename to weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/PartyApi.java index c5a3490d..3a77f97e 100644 --- a/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/DepartApi.java +++ b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/PartyApi.java @@ -8,24 +8,24 @@ import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.model.Token; -import com.foxinmy.weixin4j.qy.model.Department; +import com.foxinmy.weixin4j.qy.model.Party; import com.foxinmy.weixin4j.token.TokenHolder; /** * 部门API * - * @className DepartApi + * @className PartyApi * @author jy * @date 2014年11月18日 * @since JDK 1.7 - * @see com.foxinmy.weixin4j.qy.model.Department + * @see com.foxinmy.weixin4j.qy.model.Party * @see 管理部门说明 */ -public class DepartApi extends QyApi { +public class PartyApi extends QyApi { private final TokenHolder tokenHolder; - public DepartApi(TokenHolder tokenHolder) { + public PartyApi(TokenHolder tokenHolder) { this.tokenHolder = tokenHolder; } @@ -34,13 +34,13 @@ public class DepartApi extends QyApi { * * @param depart * 部门对象 - * @see com.foxinmy.weixin4j.qy.model.Department + * @see com.foxinmy.weixin4j.qy.model.Party * @see 创建部门说明 * @return 部门ID * @throws WeixinException */ - public int createDepart(Department depart) throws WeixinException { + public int createParty(Party depart) throws WeixinException { String department_create_uri = getRequestUri("department_create_uri"); JSONObject obj = (JSONObject) JSON.toJSON(depart); obj.remove("id"); @@ -56,15 +56,15 @@ public class DepartApi extends QyApi { * * @param depart * 部门对象 - * @see com.foxinmy.weixin4j.qy.model.Department + * @see com.foxinmy.weixin4j.qy.model.Party * @see 更新部门说明 * @return 处理结果 * @throws WeixinException */ - public JsonResult updateDepart(Department depart) throws WeixinException { + public JsonResult updateParty(Party party) throws WeixinException { String department_update_uri = getRequestUri("department_update_uri"); - JSONObject obj = (JSONObject) JSON.toJSON(depart); + JSONObject obj = (JSONObject) JSON.toJSON(party); Token token = tokenHolder.getToken(); Response response = request.post( String.format(department_update_uri, token.getAccessToken()), @@ -75,37 +75,37 @@ public class DepartApi extends QyApi { /** * 查询部门列表(以部门的order字段从小到大排列) * - * @param departId 部门ID。获取指定部门ID下的子部门 - * @see com.foxinmy.weixin4j.qy.model.Department + * @param partId 部门ID。获取指定部门ID下的子部门 + * @see com.foxinmy.weixin4j.qy.model.Party * @see 获取部门列表 * @return 部门列表 * @throws WeixinException */ - public List listDepart(int departId) throws WeixinException { + public List listParty(int partId) throws WeixinException { String department_list_uri = getRequestUri("department_list_uri"); Token token = tokenHolder.getToken(); Response response = request.post(String.format(department_list_uri, token.getAccessToken())); return JSON.parseArray(response.getAsJson().getString("department"), - Department.class); + Party.class); } /** * 删除部门(不能删除根部门;不能删除含有子部门、成员的部门) * - * @param departId + * @param partId * 部门ID * @see 删除部门说明 * @return 处理结果 * @throws WeixinException */ - public JsonResult deleteDepart(int departId) throws WeixinException { + public JsonResult deleteParty(int partId) throws WeixinException { String department_delete_uri = getRequestUri("department_delete_uri"); Token token = tokenHolder.getToken(); Response response = request.post(String.format(department_delete_uri, - token.getAccessToken(), departId)); + token.getAccessToken(), partId)); return response.getAsJsonResult(); } } diff --git a/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/weixin.properties b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/weixin.properties index f6eb71e2..b36c4b3c 100644 --- a/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/weixin.properties +++ b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/weixin.properties @@ -64,4 +64,14 @@ getcallbackip_uri={api_base_url}/getcallbackip?access_token=%s # \u83b7\u53d6\u4f01\u4e1a\u53f7\u5e94\u7528\u4fe1\u606f agent_get_uri={api_base_url}/agent/get?access_token=%s&agentid=%d # \u8bbe\u7f6e\u4f01\u4e1a\u53f7\u5e94\u7528\u4fe1\u606f -agent_set_uri={api_base_url}/agent/set?access_token=%s \ No newline at end of file +agent_set_uri={api_base_url}/agent/set?access_token=%s +# \u6279\u91cf\u9080\u8bf7\u6210\u5458\u5173\u6ce8 +batch_inviteuser_uri={api_base_url}/batch/inviteuser?access_token=%s +# \u6279\u91cf\u66f4\u65b0\u6210\u5458 +batch_syncuser_uri={api_base_url}/batch/syncuser?access_token=%s +# \u6279\u91cf\u8986\u76d6\u6210\u5458 +batch_replaceuser_uri={api_base_url}/batch/replaceuser?access_token=%s +# \u6279\u91cf\u8986\u76d6\u90e8\u95e8 +batch_replaceparty_uri={api_base_url}/batch/replaceparty?access_token=%s +# \u83b7\u53d6\u5f02\u6b65\u4efb\u52a1\u6267\u884c\u7ed3\u679c +batch_getresult_uri={api_base_url}/batch/getresult?access_token=%s&jobid=%s \ No newline at end of file diff --git a/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/BatchResult.java b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/BatchResult.java new file mode 100644 index 00000000..559e89b2 --- /dev/null +++ b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/BatchResult.java @@ -0,0 +1,99 @@ +package com.foxinmy.weixin4j.qy.model; + +import com.alibaba.fastjson.JSONArray; +import com.foxinmy.weixin4j.http.JsonResult; +import com.foxinmy.weixin4j.qy.type.BatchStatus; +import com.foxinmy.weixin4j.qy.type.BatchType; + +/** + * 异步任务执行结果 + * + * @className BatchResult + * @author jy + * @date 2015年3月31日 + * @since JDK 1.7 + * @see + */ +public class BatchResult extends JsonResult { + + private static final long serialVersionUID = 4985338631992208903L; + /** + * 任务状态 + */ + private int status; + /** + * 任务类型 + */ + private String type; + /** + * 任务运行总条数 + */ + private int total; + /** + * 目前运行百分比,当任务完成时为100 + */ + private int percentage; + /** + * 预估剩余时间(单位:分钟),当任务完成时为0 + */ + private int remaintime; + /** + * 详细的处理结果 TODO + */ + private JSONArray result; + + public BatchStatus getStatus() { + return BatchStatus.values()[status - 1]; + } + + public void setStatus(int status) { + this.status = status; + } + + public BatchType getType() { + return BatchType.valueOf(type); + } + + public void setType(String type) { + this.type = type; + } + + public int getTotal() { + return total; + } + + public void setTotal(int total) { + this.total = total; + } + + public int getPercentage() { + return percentage; + } + + public void setPercentage(int percentage) { + this.percentage = percentage; + } + + public int getRemaintime() { + return remaintime; + } + + public void setRemaintime(int remaintime) { + this.remaintime = remaintime; + } + + public JSONArray getResult() { + return result; + } + + public void setResult(JSONArray result) { + this.result = result; + } + + @Override + public String toString() { + return "BatchResult [status=" + status + ", type=" + type + ", total=" + + total + ", percentage=" + percentage + ", remaintime=" + + remaintime + ", result=" + result + "]"; + } +} diff --git a/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/Callback.java b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/Callback.java new file mode 100644 index 00000000..70cfe3b2 --- /dev/null +++ b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/Callback.java @@ -0,0 +1,52 @@ +package com.foxinmy.weixin4j.qy.model; + +import java.io.Serializable; + +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 调用某些接口时填入的回调信息 + * + * @className Callback + * @author jy + * @date 2015年3月30日 + * @since JDK 1.7 + * @see + */ +public class Callback implements Serializable { + + private static final long serialVersionUID = 8575808461248605317L; + + /** + * 企业应用接收企业号推送请求的访问协议和地址,支持http或https协议 + */ + private String url; + /** + * 用于生成签名 + */ + private String token; + /** + * 用于消息体的加密,是AES密钥的Base64编码 + */ + @JSONField(name = "encodingaeskey") + private String aesKey; + + public Callback(String url, String token, String aesKey) { + this.url = url; + this.token = token; + this.aesKey = aesKey; + } + + public String getUrl() { + return url; + } + + public String getToken() { + return token; + } + + public String getAesKey() { + return aesKey; + } + +} diff --git a/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/IdParameter.java b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/IdParameter.java new file mode 100644 index 00000000..8306b7de --- /dev/null +++ b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/IdParameter.java @@ -0,0 +1,64 @@ +package com.foxinmy.weixin4j.qy.model; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; + +/** + * id参数集 + * + * @className IdParameter + * @author jy + * @date 2015年3月30日 + * @since JDK 1.7 + * @see + */ +public class IdParameter implements Serializable { + + private static final long serialVersionUID = -2689758682205591133L; + + private Map parameterMap; + + public IdParameter() { + this.parameterMap = new HashMap(); + } + + /** + * 成员ID列表,最多支持1000个 + * + * @param userIds + * @return + */ + public IdParameter putUseIds(String... userIds) { + parameterMap.put("touser", StringUtils.join(userIds, '|')); + return this; + } + + /** + * 部门ID列表,最多支持100个 + * + * @param partyIds + * @return + */ + public IdParameter putUseIds(int... partyIds) { + parameterMap.put("toparty", StringUtils.join(partyIds, '|')); + return this; + } + + /** + * 标签ID列表 + * + * @param tagIds + * @return + */ + public IdParameter putTagIds(int... tagIds) { + parameterMap.put("totag", StringUtils.join(tagIds, '|')); + return this; + } + + public Map getParameter() { + return parameterMap; + } +} diff --git a/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/Department.java b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/Party.java similarity index 83% rename from weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/Department.java rename to weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/Party.java index 7542f6bd..ed0498e5 100644 --- a/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/Department.java +++ b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/model/Party.java @@ -5,14 +5,14 @@ import java.io.Serializable; /** * 部门对象 * - * @className Department + * @className Party * @author jy * @date 2014年11月18日 * @since JDK 1.7 * @see 管理部门说明 */ -public class Department implements Serializable { +public class Party implements Serializable { private static final long serialVersionUID = -2567893218591084288L; /** @@ -32,15 +32,15 @@ public class Department implements Serializable { */ private int order; - public Department() { + public Party() { } - public Department(String name) { + public Party(String name) { this(name, 1, 1); } - public Department(String name, int parentid, int order) { + public Party(String name, int parentid, int order) { this.name = name; this.parentid = parentid; this.order = order; @@ -80,7 +80,7 @@ public class Department implements Serializable { @Override public String toString() { - return "Department [id=" + id + ", name=" + name + ", parentid=" + return "Party [id=" + id + ", name=" + name + ", parentid=" + parentid + ", order=" + order + "]"; } } diff --git a/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/type/BatchStatus.java b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/type/BatchStatus.java new file mode 100644 index 00000000..58e2ed64 --- /dev/null +++ b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/type/BatchStatus.java @@ -0,0 +1,34 @@ +package com.foxinmy.weixin4j.qy.type; + +/** + * 异步任务的状态 + * + * @className BatchStatus + * @author jy + * @date 2015年3月31日 + * @since JDK 1.7 + * @see + */ +public enum BatchStatus { + /** + * 开始 + */ + START(1), + /** + * 进行中 + */ + PROCESS(2), + /** + * 完成 + */ + DONE(3); + private int code; + + BatchStatus(int code) { + this.code = code; + } + + public int getCode() { + return code; + } +} diff --git a/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/type/BatchType.java b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/type/BatchType.java new file mode 100644 index 00000000..9de8b673 --- /dev/null +++ b/weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/type/BatchType.java @@ -0,0 +1,39 @@ +package com.foxinmy.weixin4j.qy.type; + +/** + * 异步任务的类型 + * + * @className BatchType + * @author jy + * @date 2015年3月31日 + * @since JDK 1.7 + * @see + */ +public enum BatchType { + /** + * 增量更新成员 + */ + SYNC_USER(1), + /** + * 全量覆盖成员 + */ + REPLACE_USER(2), + /** + * 邀请成员关注 + */ + INVITE_USER(3), + /** + * 全量覆盖部门 + */ + REPLACE_PARTY(4); + + private int code; + + BatchType(int code) { + this.code = code; + } + + public int getCode() { + return code; + } +} diff --git a/weixin4j-qy/weixin4j-qy-api/src/test/java/com/foxinmy/weixin4j/qy/test/BatchTest.java b/weixin4j-qy/weixin4j-qy-api/src/test/java/com/foxinmy/weixin4j/qy/test/BatchTest.java new file mode 100644 index 00000000..e5dd07da --- /dev/null +++ b/weixin4j-qy/weixin4j-qy-api/src/test/java/com/foxinmy/weixin4j/qy/test/BatchTest.java @@ -0,0 +1,39 @@ +package com.foxinmy.weixin4j.qy.test; + +import org.junit.Before; +import org.junit.Test; + +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.qy.api.BatchApi; +import com.foxinmy.weixin4j.qy.model.BatchResult; +import com.foxinmy.weixin4j.qy.model.Callback; + +/** + * 异步任务测试 + * + * @className BatchTest + * @author jy + * @date 2015年3月31日 + * @since JDK 1.7 + * @see + */ +public class BatchTest extends TokenTest { + public BatchApi batchApi; + + @Before + public void init() { + this.batchApi = new BatchApi(tokenHolder); + } + + @Test + public void replaceparty() throws WeixinException { + String jobId = batchApi.replaceparty("mediaId", new Callback("url", "token", "aesKey")); + System.err.println(jobId); + } + + @Test + public void getresult() throws WeixinException { + BatchResult result = batchApi.getresult("jobId"); + System.err.println(result); + } +} diff --git a/weixin4j-qy/weixin4j-qy-api/src/test/java/com/foxinmy/weixin4j/qy/test/DepartTest.java b/weixin4j-qy/weixin4j-qy-api/src/test/java/com/foxinmy/weixin4j/qy/test/PartyTest.java similarity index 58% rename from weixin4j-qy/weixin4j-qy-api/src/test/java/com/foxinmy/weixin4j/qy/test/DepartTest.java rename to weixin4j-qy/weixin4j-qy-api/src/test/java/com/foxinmy/weixin4j/qy/test/PartyTest.java index 811d38f8..dcdcff04 100644 --- a/weixin4j-qy/weixin4j-qy-api/src/test/java/com/foxinmy/weixin4j/qy/test/DepartTest.java +++ b/weixin4j-qy/weixin4j-qy-api/src/test/java/com/foxinmy/weixin4j/qy/test/PartyTest.java @@ -8,51 +8,51 @@ import org.junit.Test; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.JsonResult; -import com.foxinmy.weixin4j.qy.api.DepartApi; -import com.foxinmy.weixin4j.qy.model.Department; +import com.foxinmy.weixin4j.qy.api.PartyApi; +import com.foxinmy.weixin4j.qy.model.Party; /** * 部门API测试 * - * @className DepartTest + * @className PartyTest * @author jy * @date 2014年11月18日 * @since JDK 1.7 * @see */ -public class DepartTest extends TokenTest { - public DepartApi departApi; +public class PartyTest extends TokenTest { + public PartyApi partyApi; @Before public void init() { - this.departApi = new DepartApi(tokenHolder); + this.partyApi = new PartyApi(tokenHolder); } @Test public void create() throws WeixinException { - Department depart = new Department("苦逼组"); - int id = departApi.createDepart(depart); + Party Party = new Party("苦逼组"); + int id = partyApi.createParty(Party); Assert.assertTrue(id > 0); } @Test public void update() throws WeixinException { - Department depart = new Department("苦逼组111"); - depart.setId(2); - JsonResult result = departApi.updateDepart(depart); + Party Party = new Party("苦逼组111"); + Party.setId(2); + JsonResult result = partyApi.updateParty(Party); Assert.assertEquals("updated", result.getDesc()); } @Test public void list() throws WeixinException { - List list = departApi.listDepart(1); + List list = partyApi.listParty(1); Assert.assertFalse(list.isEmpty()); System.out.println(list); } @Test public void delete() throws WeixinException { - JsonResult result = departApi.deleteDepart(2); + JsonResult result = partyApi.deleteParty(2); Assert.assertEquals("deleted", result.getDesc()); } } diff --git a/weixin4j-qy/weixin4j-qy-server/README.md b/weixin4j-qy/weixin4j-qy-server/README.md index 9013090d..adee59c9 100644 --- a/weixin4j-qy/weixin4j-qy-server/README.md +++ b/weixin4j-qy/weixin4j-qy-server/README.md @@ -71,4 +71,8 @@ weixin4j-qy-server * 2015-03-25 - + 新增deploy.xml远程部署ant脚本 \ No newline at end of file + + 新增deploy.xml远程部署ant脚本 + +* 2015-04-01 + + + 新增批量任务执行完成事件 \ No newline at end of file diff --git a/weixin4j-qy/weixin4j-qy-server/src/main/java/com/foxinmy/weixin4j/qy/action/event/BatchJobAction.java b/weixin4j-qy/weixin4j-qy-server/src/main/java/com/foxinmy/weixin4j/qy/action/event/BatchJobAction.java new file mode 100644 index 00000000..49912608 --- /dev/null +++ b/weixin4j-qy/weixin4j-qy-server/src/main/java/com/foxinmy/weixin4j/qy/action/event/BatchJobAction.java @@ -0,0 +1,21 @@ +package com.foxinmy.weixin4j.qy.action.event; + +import com.foxinmy.weixin4j.action.DebugAction; +import com.foxinmy.weixin4j.action.mapping.ActionAnnotation; +import com.foxinmy.weixin4j.msg.event.BatchjobresultMessage; +import com.foxinmy.weixin4j.type.EventType; +import com.foxinmy.weixin4j.type.MessageType; + +/** + * 异步任务完成事件 + * + * @className BatchJobAction + * @author jy + * @date 2015年3月31日 + * @since JDK 1.7 + * @see com.foxinmy.weixin4j.msg.event.BatchjobresultMessage + */ +@ActionAnnotation(msgType = MessageType.event, eventType = { EventType.batch_job_result }) +public class BatchJobAction extends DebugAction { + +}