From a874973428eaad7e547d4836e490f752845bb771 Mon Sep 17 00:00:00 2001 From: fengyapeng Date: Tue, 20 Dec 2016 10:27:29 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E4=BF=AE=E6=94=B9weixin4j=20=EF=BC=8C?= =?UTF-8?q?=E4=BD=BF=E5=85=B6=E6=9B=B4=E9=80=82=E7=94=A8=E4=BA=8Ewyying?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin4j/exception/WeixinException.java | 101 ++++++++++-------- .../http/weixin/WeixinRequestExecutor.java | 30 +++--- .../foxinmy/weixin4j/http/weixin/error.xml | 78 +++++++++++--- .../com/foxinmy/weixin4j/model/Token.java | 32 +++++- 4 files changed, 170 insertions(+), 71 deletions(-) diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/exception/WeixinException.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/exception/WeixinException.java index 40a5c752..aa6b5681 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/exception/WeixinException.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/exception/WeixinException.java @@ -2,65 +2,82 @@ package com.foxinmy.weixin4j.exception; import com.foxinmy.weixin4j.util.StringUtil; import com.foxinmy.weixin4j.util.WeixinErrorUtil; +import com.foxinmy.weixin4j.util.WeixinErrorUtil2; /** * 调用微信接口抛出的异常 * - * @className WeixinException * @author jinyu(foxinmy@gmail.com) + * @className WeixinException * @date 2014年4月10日 - * @since JDK 1.6 * @see + * @since JDK 1.6 */ public class WeixinException extends Exception { - private static final long serialVersionUID = 7148145661883468514L; + private static final long serialVersionUID = 7148145661883468514L; - private String code; - private String desc; + private String code; + private String desc; + private String describeErrorMsg; - public WeixinException(String code, String desc) { - this.code = code; - this.desc = desc; - } + public WeixinException(String code, String desc) { + this(code, desc, null); + } - public WeixinException(String desc) { - this.code = "-1"; - this.desc = desc; - } - public WeixinException(Throwable e) { - super(e); - } + public WeixinException(String errorCode, String errorMsg, String describeErrorMsg) { + this.code = errorCode; + this.desc = errorMsg; + if (describeErrorMsg == null) { + this.describeErrorMsg = errorMsg; + } else { + this.describeErrorMsg = describeErrorMsg; + } + } - public WeixinException(String message, Throwable cause) { - super(message, cause); - } + public WeixinException(String desc) { + this.code = "-1"; + this.desc = desc; + } - public String getErrorCode() { - return code; - } + public String getDescribeErrorMsg() { + return describeErrorMsg; + } - public String getErrorDesc() { - return desc; - } - public String getErrorText() { - return WeixinErrorUtil.getText(code); - } + public WeixinException(Throwable e) { + super(e); + } - @Override - public String getMessage() { - if (StringUtil.isNotBlank(code)) { - StringBuilder buf = new StringBuilder(); - buf.append(code).append(" >> ").append(desc); - String text = getErrorText(); - if (StringUtil.isNotBlank(text)) { - buf.append(" >> ").append(text); - } - return buf.toString(); - } else { - return super.getMessage(); - } - } + public WeixinException(String message, Throwable cause) { + super(message, cause); + } + + public String getErrorCode() { + return code; + } + + public String getErrorDesc() { + return desc; + } + + public String getErrorText() { + return WeixinErrorUtil2.getText(code); + } + + @Override + public String getMessage() { + if (StringUtil.isNotBlank(code)) { + StringBuilder buf = new StringBuilder(); + buf.append(code).append(" >> ").append(desc); + String text = getErrorText(); + if (StringUtil.isNotBlank(text)) { + buf.append(" >> ").append(text); + } + return buf.toString(); + } else { + return super.getMessage(); + } + } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/WeixinRequestExecutor.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/WeixinRequestExecutor.java index f24cf664..8f4eb32d 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/WeixinRequestExecutor.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/WeixinRequestExecutor.java @@ -28,21 +28,24 @@ import com.foxinmy.weixin4j.http.message.XmlMessageConverter; import com.foxinmy.weixin4j.logging.InternalLogLevel; import com.foxinmy.weixin4j.logging.InternalLogger; import com.foxinmy.weixin4j.logging.InternalLoggerFactory; + + import com.foxinmy.weixin4j.util.Consts; +import com.foxinmy.weixin4j.util.WeixinErrorUtil2; /** * 负责微信请求的执行 * + * @author jy * @className WeixinRequestExecutor * @author jinyu(foxinmy@gmail.com) * @date 2015年8月15日 - * @since JDK 1.6 * @see + * @since JDK 1.6 */ public class WeixinRequestExecutor { - protected final InternalLogger logger = InternalLoggerFactory - .getInstance(getClass()); + protected final InternalLogger logger = InternalLoggerFactory.getInstance(getClass()); private static final String SUCCESS_CODE = ",0,success,"; @@ -58,7 +61,7 @@ public class WeixinRequestExecutor { /** * Post方法执行微信请求 - * + * * @param url * 请求URL * @param body @@ -75,7 +78,7 @@ public class WeixinRequestExecutor { /** * Post方法执行微信请求,用于文件上传 - * + * * @param url * 请求URL * @param bodyParts @@ -97,7 +100,7 @@ public class WeixinRequestExecutor { /** * Get方法执行微信请求 - * + * * @param url * 请求URL,如:https://api.weixin.qq.com/cgi-bin/token * @param parameters @@ -118,7 +121,7 @@ public class WeixinRequestExecutor { /** * 执行微信请求 - * + * * @param request * 微信请求 * @return 微信响应 @@ -130,6 +133,9 @@ public class WeixinRequestExecutor { logger.debug("weixin request >> " + request.getMethod() + " " + request.getURI().toString()); } + if(request.getEntity() instanceof StringEntity){ + logger.debug("weixin request body >> " + ((StringEntity) request.getEntity()).getContentString()); + } HttpResponse httpResponse = httpClient.execute(request); WeixinResponse response = new WeixinResponse(httpResponse); handleResponse(response); @@ -141,7 +147,7 @@ public class WeixinRequestExecutor { /** * 响应内容是否为流 - * + * * @param response * 微信响应 * @return true/false @@ -159,7 +165,7 @@ public class WeixinRequestExecutor { /** * handle the weixin response - * + * * @param response * 微信请求响应 * @throws WeixinException @@ -182,7 +188,7 @@ public class WeixinRequestExecutor { if (!SUCCESS_CODE.contains(String.format(",%s,", result.getReturnCode() .toLowerCase()))) { throw new WeixinException(result.getReturnCode(), - result.getReturnMsg()); + result.getReturnMsg(),WeixinErrorUtil2.getText(result.getReturnCode())); } if (XmlMessageConverter.GLOBAL.canConvert(XmlResult.class, response)) { try { @@ -191,7 +197,7 @@ public class WeixinRequestExecutor { if (!SUCCESS_CODE.contains(String.format(",%s,", xmlResult .getResultCode().toLowerCase()))) { throw new WeixinException(xmlResult.getErrCode(), - xmlResult.getErrCodeDes()); + xmlResult.getErrCodeDes(),WeixinErrorUtil2.getText(xmlResult.getErrCode())); } } catch (IOException e) { ; @@ -205,7 +211,7 @@ public class WeixinRequestExecutor { /** * 创建 SSL微信请求对象 - * + * * @param password * 加载密钥 * @param inputStream diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/error.xml b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/error.xml index a520e717..aa0ec8d8 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/error.xml +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/error.xml @@ -2,14 +2,16 @@ - - -1 - 系统繁忙,请稍后再试 - 0 请求成功 + + -1 + system error + 微信系统繁忙,请稍候再试 + + 40001 获取access_token时AppSecret错误,或者access_token无效 @@ -36,7 +38,8 @@ 40007 - 无效的media_id + invalid media_id + 请检查您的素材! 40008 @@ -133,7 +136,7 @@ 40031 - 不合法的openid列表 + 不合法的粉丝列表 40032 @@ -339,6 +342,10 @@ 40116 不合法的Code码。 + + 40113 + 不支持的文件类型 + 40117 分组名字不合法 @@ -375,6 +382,15 @@ 40132 微信号不合法 + + 40130 + 最少选择两名粉丝 + + + 40132 + invalid username + 无效的微信号 + 40137 不支持的图片格式 @@ -533,7 +549,8 @@ 43004 - 需要接收者关注 + require subscribe + 未关注公众号 43005 @@ -593,19 +610,23 @@ 45001 - 多媒体文件大小超过限制 + media size out of limit + 多媒体文件大小超过微信限制 45002 - 消息内容超过限制 + content size out of limit + 发送内容超过限制 45003 - 标题字段超过限制 + title size out of limit + 标题超过限制 45004 - 描述字段超过限制 + description size out of limit + 描述超过限制 45005 @@ -651,6 +672,10 @@ 45021 字段超过长度限制,请参考相应接口的字段说明。 + + 45028 + 群发次数超过限制 + 45022 应用名字长度不合法,合法长度为2-16个字 @@ -715,10 +740,32 @@ 45058 不能修改0/1/2这三个系统默认保留的标签 + + 48001 + 公众号没有调用该接口的权限 + + + 48002 + 公众号没有调用该接口的权限 + + + 48003 + 请登录公众号后台,打开“群发功能”,同意腾讯群发消息声明 + + 45059 有粉丝身上的标签数已经超过限制 + + 48005 + 此素材被自定义菜单引用,请先解除引用关系再编辑素材 + forbid to delete material used by auto-reply or menu hint: [JMOD7a0063e292] + + + 61450 + 系统错误(system error) + 45157 标签名非法,请注意不能和其他标签重名 @@ -2420,8 +2467,8 @@ 金额不匹配,报关的订单金额必须和支付的金额一致,请检查报关订单的金额是否正确 - POST_DATA_EMPTY - post数据为空,post数据不能为空,请检查post数据是否为空 + 9001007 + 上传文件无效 REQUIRE_POST_METHOD @@ -2432,9 +2479,8 @@ 输入的参数xml格式有误,检查输入的xml格式是否正确 - SECOND_OVER_LIMITED - 企业红包的按分钟发放受限,每分钟发送红包数量不得超过1800个;(可联系微信支付wxhongbao@tencent.com调高额度) - + 9001010 + 文件上传到微信失败 SENDNUM_LIMIT diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Token.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Token.java index a25f8755..1bfcec19 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Token.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Token.java @@ -3,6 +3,7 @@ package com.foxinmy.weixin4j.model; import java.util.HashMap; import java.util.Map; +import com.alibaba.fastjson.annotation.JSONField; import com.foxinmy.weixin4j.cache.Cacheable; /** @@ -25,10 +26,12 @@ public class Token implements Cacheable { /** * 获取到的凭证 */ + @JSONField(name = "access_token") private String accessToken; /** * 凭证有效时间,单位:毫秒 */ + @JSONField(name = "expires_in") private long expires; /** * token创建的时间,单位:毫秒 @@ -39,6 +42,11 @@ public class Token implements Cacheable { */ private Map extra; + /** + * 请求返回的原始结果 + */ + private String originalResult; + /** * 永不过期、创建时间为当前时间戳的token对象 * @@ -55,7 +63,7 @@ public class Token implements Cacheable { * @param accessToken * 凭证字符串 * @param expires - * 过期时间 单位毫秒 + * 过期时间 单位秒 */ public Token(String accessToken, long expires) { this(accessToken, expires, System.currentTimeMillis()); @@ -77,6 +85,26 @@ public class Token implements Cacheable { this.extra = new HashMap(); } + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public void setExpires(long expires) { + this.expires = expires; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + public String getOriginalResult() { + return originalResult; + } + + public void setOriginalResult(String originalResult) { + this.originalResult = originalResult; + } + public String getAccessToken() { return accessToken; } @@ -100,6 +128,8 @@ public class Token implements Cacheable { return this; } + + @Override public String toString() { return "Token [accessToken=" + accessToken + ", expires=" + expires From ddd1310ac958a9797e23e00cb35cee33931464a7 Mon Sep 17 00:00:00 2001 From: fengyapeng Date: Tue, 20 Dec 2016 10:34:11 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E6=94=AF=E4=BB=98=E7=AD=89=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 44 ++- weixin4j-base/pom.xml | 2 +- .../java/com/foxinmy/weixin4j/api/MchApi.java | 2 +- .../java/com/foxinmy/weixin4j/api/PayApi.java | 290 +++++++++++++++++- .../weixin4j/http/entity/StringEntity.java | 10 +- .../weixin4j/model/paging/Pagedata.java | 4 + .../foxinmy/weixin4j/payment/PayPackage.java | 41 +++ .../foxinmy/weixin4j/payment/PayRequest.java | 2 + .../weixin4j/payment/WeixinPayProxy.java | 2 +- .../weixin4j/payment/mch/APPPayRequest.java | 4 +- .../payment/mch/AbstractPayRequest.java | 12 +- .../weixin4j/payment/mch/JSAPIPayRequest.java | 4 +- .../weixin4j/payment/mch/MICROPayRequest.java | 12 + .../weixin4j/payment/mch/MchPayPackage.java | 88 +++++- .../weixin4j/payment/mch/MchPayRequest.java | 6 + .../payment/mch/NATIVEPayRequest.java | 4 +- .../foxinmy/weixin4j/payment/mch/Order.java | 2 +- .../foxinmy/weixin4j/payment/mch/PrePay.java | 10 + .../weixin4j/payment/mch/Redpacket.java | 37 +++ .../weixin4j/payment/mch/WAPPayRequest.java | 4 +- .../weixin4j/sign/WeixinPaymentSignature.java | 62 ++-- .../com/foxinmy/weixin4j/util/FileUtil.java | 277 +++++++++-------- .../com/foxinmy/weixin4j/util/IOUtil.java | 131 ++++---- .../weixin4j/util/WeixinErrorUtil.java | 31 +- weixin4j-mp/pom.xml | 2 +- .../com/foxinmy/weixin4j/mp/api/MassApi.java | 3 +- weixin4j-qy/pom.xml | 2 +- 27 files changed, 811 insertions(+), 277 deletions(-) diff --git a/pom.xml b/pom.xml index 065acfa9..7ee01f65 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.foxinmy weixin4j - 1.7.3 + 1.7.3-SNAPSHOT pom weixin4j https://github.com/foxinmy/weixin4j @@ -44,7 +44,6 @@ weixin4j-mp weixin4j-qy weixin4j-server - weixin4j-example UTF-8 @@ -54,6 +53,18 @@ + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + + jar + + + + org.apache.maven.plugins maven-compiler-plugin @@ -211,8 +222,8 @@ src/main/resources - **/*.xml - **/*.properties + *.xml + *.properties @@ -248,14 +259,27 @@ + - - oss-snapshot - https://oss.sonatype.org/content/repositories/snapshots/ - - oss-release - https://oss.sonatype.org/service/local/staging/deploy/maven2/ + Project Releases + Project Releases + http://repo.wyying.com/nexus/content/repositories/releases/ + + Project Snapshots + Project Snapshots + http://repo.wyying.com/nexus/content/repositories/snapshots/ + + + + + + + + + + + \ No newline at end of file diff --git a/weixin4j-base/pom.xml b/weixin4j-base/pom.xml index ad39d041..1457cf0e 100644 --- a/weixin4j-base/pom.xml +++ b/weixin4j-base/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.7.3 + 1.7.3-SNAPSHOT weixin4j-base weixin4j-base diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/MchApi.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/MchApi.java index 86a878fc..221a067b 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/MchApi.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/MchApi.java @@ -36,7 +36,7 @@ public class MchApi extends BaseApi { } protected final WeixinPayAccount weixinAccount; - protected final WeixinSignature weixinSignature; + protected final WeixinPaymentSignature weixinSignature; private volatile WeixinRequestExecutor weixinSSLExecutor; public MchApi(WeixinPayAccount weixinAccount) { diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/PayApi.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/PayApi.java index 8583da5f..3dfeaec8 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/PayApi.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/PayApi.java @@ -16,6 +16,7 @@ import java.util.Map; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.exception.WeixinPayException; import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.http.weixin.XmlResult; import com.foxinmy.weixin4j.model.WeixinPayAccount; @@ -83,8 +84,14 @@ public class PayApi extends MchApi { String payJsRequestXml = XmlStream.toXML(payPackage); WeixinResponse response = weixinExecutor.post( getRequestUri("order_create_uri"), payJsRequestXml); - return response.getAsObject(new TypeReference() { - }); + boolean validatePaySign = weixinSignature.validatePaySign(response); + if(validatePaySign) { + PrePay prePay = response.getAsObject(new TypeReference() { + }); + prePay.setResponse(response.getAsString()); + return prePay; + } + throw new WeixinPayException("验证签名信息失败,返回数据可能被篡改"); } /** @@ -122,19 +129,20 @@ public class PayApi extends MchApi { MICROPayRequest microPayRequest = response .getAsObject(new TypeReference() { }); + microPayRequest.setResponse(response.getAsString()); microPayRequest.setPaymentAccount(weixinAccount); return microPayRequest; } PrePay prePay = createPrePay(payPackage); if (TradeType.APP.name().equals(tradeType)) { - return new APPPayRequest(prePay.getPrepayId(), weixinAccount); + return new APPPayRequest(prePay, weixinAccount); } else if (TradeType.JSAPI.name().equals(tradeType)) { - return new JSAPIPayRequest(prePay.getPrepayId(), weixinAccount); + return new JSAPIPayRequest(prePay, weixinAccount); } else if (TradeType.NATIVE.name().equals(tradeType)) { - return new NATIVEPayRequest(prePay.getPrepayId(), + return new NATIVEPayRequest(prePay, prePay.getCodeUrl(), weixinAccount); } else if (TradeType.WAP.name().equals(tradeType)) { - return new WAPPayRequest(prePay.getPrepayId(), weixinAccount); + return new WAPPayRequest(prePay, weixinAccount); } else { throw new WeixinException("unknown tradeType:" + tradeType); } @@ -170,6 +178,36 @@ public class PayApi extends MchApi { return createPayRequest(payPackage); } + /** + * 创建JSAPI支付请求对象 + * + * @param openId + * 用户ID + * @param body + * 订单描述 + * @param outTradeNo + * 订单号 + * @param totalFee + * 订单总额(元) + * @param notifyUrl + * 支付通知地址 + * @param createIp + * ip地址 + * @param attach + * 附加数据 非必填 + * @see com.foxinmy.weixin4j.payment.mch.JSAPIPayRequest + * @return JSAPI支付对象 + * @throws WeixinException + */ + public MchPayRequest createJSPayRequest(String openId, String body, + String outTradeNo, long totalFee, String notifyUrl, + String createIp, String attach) throws WeixinException { + MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, + totalFee, notifyUrl, createIp, TradeType.JSAPI, openId, null, + null, attach); + return createPayRequest(payPackage); + } + /** *

* 生成编辑地址请求 @@ -271,6 +309,43 @@ public class PayApi extends MchApi { return new NativePayResponse(weixinAccount, prePay.getPrepayId()); } + /** + * 创建Native支付(扫码支付)回调对象【模式一】 + * + * @param productId + * 商品ID + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @return Native回调对象 + * @see com.foxinmy.weixin4j.payment.mch.NativePayResponse + * @see 扫码支付 + * + * @see 模式一 + * + * @throws WeixinException + */ + public NativePayResponse createNativePayResponse(String productId, + String body, String outTradeNo, long totalFee, String notifyUrl, + String createIp, String attach) throws WeixinException { + MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, + totalFee, notifyUrl, createIp, TradeType.NATIVE, null, null, + productId, attach); + PrePay prePay = createPrePay(payPackage); + return new NativePayResponse(weixinAccount, prePay.getPrepayId()); + } + /** * 创建Native支付(扫码支付)链接【模式二】 * @@ -307,6 +382,42 @@ public class PayApi extends MchApi { return createPayRequest(payPackage); } + /** + * 创建Native支付(扫码支付)链接【模式二】 + * + * @param productId + * 商品ID + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @return Native支付对象 + * @see com.foxinmy.weixin4j.payment.mch.NATIVEPayRequest + * @see 扫码支付 + * + * @see 模式二 + * + * @throws WeixinException + */ + public MchPayRequest createNativePayRequest(String productId, String body, + String outTradeNo, long totalFee, String notifyUrl, + String createIp, String attach) throws WeixinException { + MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, + totalFee, notifyUrl, createIp, TradeType.NATIVE, null, null, + productId, attach); + return createPayRequest(payPackage); + } + /** * 创建APP支付请求对象 * @@ -338,6 +449,37 @@ public class PayApi extends MchApi { return createPayRequest(payPackage); } + /** + * 创建APP支付请求对象 + * + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @return APP支付对象 + * @see com.foxinmy.weixin4j.payment.mch.APPPayRequest + * @see + * APP支付 + * @throws WeixinException + */ + public MchPayRequest createAppPayRequest(String body, String outTradeNo, + long totalFee, String notifyUrl, String createIp, String attach) + throws WeixinException { + MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, + totalFee, notifyUrl, createIp, TradeType.APP, null, null, null, + attach); + return createPayRequest(payPackage); + } + /** * 创建WAP支付请求对象 * @@ -369,6 +511,37 @@ public class PayApi extends MchApi { return createPayRequest(payPackage); } + /** + * 创建WAP支付请求对象 + * + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param notifyUrl + * 支付回调URL + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @return WAP支付对象 + * @see com.foxinmy.weixin4j.payment.mch.WAPPayRequest + * @see WAP支付 + * + * @throws WeixinException + */ + public MchPayRequest createWapPayRequest(String body, String outTradeNo, + long totalFee, String notifyUrl, String createIp, String attach) + throws WeixinException { + MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, + totalFee, notifyUrl, createIp, TradeType.WAP, null, null, null, + attach); + return createPayRequest(payPackage); + } + /** * 提交被扫支付 * @@ -393,11 +566,43 @@ public class PayApi extends MchApi { * @throws WeixinException */ public MchPayRequest createMicroPayRequest(String authCode, String body, - String outTradeNo, double totalFee, String createIp, String attach) + String outTradeNo, double totalFee, String createIp, String attach) throws WeixinException { MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, - totalFee, null, createIp, TradeType.MICROPAY, null, authCode, - null, attach); + totalFee, null, createIp, TradeType.MICROPAY, null, authCode, + null, attach); + return createPayRequest(payPackage); + } + + /** + * 提交被扫支付 + * + * @param authCode + * 扫码支付授权码 ,设备读取用户微信中的条码或者二维码信息 + * @param body + * 商品描述 + * @param outTradeNo + * 商户内部唯一订单号 + * @param totalFee + * 商品总额 单位元 + * @param createIp + * 订单生成的机器 IP + * @param attach + * 附加数据 非必填 + * @return 支付的订单信息 + * @see com.foxinmy.weixin4j.payment.mch.MICROPayRequest + * @see com.foxinmy.weixin4j.payment.mch.Order + * @see + * 提交被扫支付API + * @throws WeixinException + */ + public MchPayRequest createMicroPayRequest(String authCode, String body, + String outTradeNo, long totalFee, String createIp, String attach) + throws WeixinException { + MchPayPackage payPackage = new MchPayPackage(body, outTradeNo, + totalFee, null, createIp, TradeType.MICROPAY, null, authCode, + null, attach); return createPayRequest(payPackage); } @@ -468,13 +673,51 @@ public class PayApi extends MchApi { double totalFee, double refundFee, CurrencyType refundFeeType, String opUserId, RefundAccountType refundAccountType) throws WeixinException { + return applyRefund(idQuery, outRefundNo, DateUtil.formatYuan2Fen(totalFee), DateUtil.formatYuan2Fen(refundFee), refundFeeType, opUserId, + refundAccountType); + } + + /** + * 申请退款(请求需要双向证书) + *

+ * 当交易发生之后一段时间内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付款退还给买家,微信支付将在收到退款请求并且验证成功之后, + * 按照退款规则将支付款按原路退到买家帐号上。 + *

+ *

+ * 1.交易时间超过半年的订单无法提交退款; + * 2.微信支付退款支持单笔交易分多次退款,多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。一笔退款失败后重新提交 + * ,要采用原来的退款单号。总退款金额不能超过用户实际支付金额。 + *

+ * + * @param idQuery + * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: + * transaction_id> out_trade_no + * @param outRefundNo + * 商户系统内部的退款单号,商 户系统内部唯一,同一退款单号多次请求只退一笔 + * @param totalFee + * 订单总金额,单位为元 + * @param refundFee + * 退款总金额,单位为元,可以做部分退款 + * @param refundFeeType + * 货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY + * @param opUserId + * 操作员帐号, 默认为商户号 + * @param refundAccountType + * @return 退款申请结果 + * @see com.foxinmy.weixin4j.payment.mch.RefundResult + * @see + * 申请退款API + * @since V3 + * @throws WeixinException + */ + public RefundResult applyRefund(IdQuery idQuery, String outRefundNo, long totalFee, long refundFee, CurrencyType refundFeeType, + String opUserId, RefundAccountType refundAccountType) throws WeixinException { WeixinResponse response = null; Map map = createBaseRequestMap(idQuery); map.put("out_refund_no", outRefundNo); - map.put("total_fee", - Integer.toString(DateUtil.formatYuan2Fen(totalFee))); - map.put("refund_fee", - Integer.toString(DateUtil.formatYuan2Fen(refundFee))); + map.put("total_fee", String.valueOf(totalFee)); + map.put("refund_fee", String.valueOf(refundFee)); if (StringUtil.isBlank(opUserId)) { opUserId = weixinAccount.getMchId(); } @@ -505,7 +748,7 @@ public class PayApi extends MchApi { * 商户系统内部的退款单号,商 户系统内部唯一,同一退款单号多次请求只退一笔 * @param totalFee * 订单总金额,单位为元 - * @see {@link #applyRefund(IdQuery, String, double, double,CurrencyType, String)} + * @see {@link #applyRefund(IdQuery, String, double, double,CurrencyType, String,RefundAccountType)} */ public RefundResult applyRefund(IdQuery idQuery, String outRefundNo, double totalFee) throws WeixinException { @@ -513,6 +756,23 @@ public class PayApi extends MchApi { null, null); } + /** + * 退款申请(全额退款) + * + * @param idQuery + * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: + * transaction_id> out_trade_no + * @param outRefundNo + * 商户系统内部的退款单号,商 户系统内部唯一,同一退款单号多次请求只退一笔 + * @param totalFee + * 订单总金额,单位为元 + * @see {@link #applyRefund(IdQuery, String, double, double,CurrencyType, String,RefundAccountType)} + */ + public RefundResult applyRefund(IdQuery idQuery, String outRefundNo, + long totalFee) throws WeixinException { + return applyRefund(idQuery, outRefundNo, totalFee, totalFee, null, null, null); + } + /** * 冲正订单(需要证书)
当支付返回失败,或收银系统超时需要取消交易,可以调用该接口
接口逻辑:支 * 付失败的关单,支付成功的撤销支付
7天以内的单可撤销,其他正常支付的单 @@ -749,4 +1009,6 @@ public class PayApi extends MchApi { return response.getAsObject(new TypeReference() { }); } + + } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/entity/StringEntity.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/entity/StringEntity.java index 5d5aecc9..d5a0db37 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/entity/StringEntity.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/entity/StringEntity.java @@ -6,9 +6,11 @@ import java.io.InputStream; import java.io.OutputStream; import com.foxinmy.weixin4j.http.ContentType; +import com.foxinmy.weixin4j.util.Consts; public class StringEntity implements HttpEntity { - private final byte[] content; + + private final byte[] content; private final ContentType contentType; public StringEntity(String body) { @@ -40,4 +42,10 @@ public class StringEntity implements HttpEntity { outstream.write(this.content); outstream.flush(); } + + + public String getContentString() { + return new String(this.content, Consts.UTF_8); + } + } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/paging/Pagedata.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/paging/Pagedata.java index a5ecab70..684a59e6 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/paging/Pagedata.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/paging/Pagedata.java @@ -55,6 +55,10 @@ public class Pagedata implements Serializable, Iterable { return pageable == null ? null : pageable.getSort(); } + public List getContent() { + return content; + } + @Override public Iterator iterator() { return hasContent() ? content.iterator() : null; diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/PayPackage.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/PayPackage.java index 591b1ffb..00746673 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/PayPackage.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/PayPackage.java @@ -127,6 +127,47 @@ public class PayPackage extends MerchantResult { this.goodsTag = goodsTag; } + /** + * 订单对象 + * + * @param body + * 订单描述 必填 + * @param detail + * 订单详情 非必填 + * @param outTradeNo + * 商户内部ID 必填 + * @param totalFee + * 订单总额 必填 单位为分 + * @param notifyUrl + * 回调地址 必填 + * @param createIp + * 生成订单数据的机器IP 必填 + * @param attach + * 附加数据 非必填 + * @param timeStart + * 订单生成时间 非必填 + * @param timeExpire + * 订单失效时间 非必填 + * @param goodsTag + * 订单标记 非必填 + */ + public PayPackage(String body, String detail, String outTradeNo, + long totalFee, String notifyUrl, String createIp, String attach, + Date timeStart, Date timeExpire, String goodsTag) { + this.body = body; + this.detail = detail; + this.outTradeNo = outTradeNo; + this.totalFee = Long.valueOf(totalFee).intValue(); + this.notifyUrl = notifyUrl; + this.createIp = createIp; + this.attach = attach; + this.timeStart = timeStart != null ? DateUtil + .fortmat2yyyyMMddHHmmss(timeStart) : null; + this.timeExpire = timeExpire != null ? DateUtil + .fortmat2yyyyMMddHHmmss(timeExpire) : null; + this.goodsTag = goodsTag; + } + public String getBody() { return body; } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/PayRequest.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/PayRequest.java index 2eb0ebbf..c6e2d728 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/PayRequest.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/PayRequest.java @@ -36,6 +36,7 @@ public class PayRequest extends PayBaseInfo { @JSONField(serialize = false) private String partnerId; + protected PayRequest() { // jaxb required } @@ -69,6 +70,7 @@ public class PayRequest extends PayBaseInfo { this.partnerId = partnerId; } + @Override public String toString() { return "package" + packageInfo + ", prepayId=" + prepayId diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/WeixinPayProxy.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/WeixinPayProxy.java index 7df325e4..5eb24ef2 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/WeixinPayProxy.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/WeixinPayProxy.java @@ -468,7 +468,7 @@ public class WeixinPayProxy { * * @throws IOException * - * @see {@link #applyRefund(IdQuery, String, double, double, String,CurrencyType)} + * @see {@link #applyRefund(IdQuery, String, double, double,CurrencyType,String,RefundAccountType)} */ public RefundResult applyRefund(IdQuery idQuery, String outRefundNo, double totalFee) throws WeixinException { diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/APPPayRequest.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/APPPayRequest.java index 66e1a8a7..e930a472 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/APPPayRequest.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/APPPayRequest.java @@ -20,8 +20,8 @@ import com.foxinmy.weixin4j.util.MapUtil; * href="https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_1">APP支付 */ public class APPPayRequest extends AbstractPayRequest { - public APPPayRequest(String prePayId, WeixinPayAccount payAccount) { - super(prePayId, payAccount); + public APPPayRequest(PrePay prePay, WeixinPayAccount payAccount) { + super(prePay.getPrepayId(),prePay.getResponse(), payAccount); } @Override diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/AbstractPayRequest.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/AbstractPayRequest.java index 7e344dd8..246a8b21 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/AbstractPayRequest.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/AbstractPayRequest.java @@ -10,10 +10,14 @@ public abstract class AbstractPayRequest implements MchPayRequest { private final WeixinPayAccount paymentAccount; protected final WeixinSignature weixinSignature; - public AbstractPayRequest(String prePayId, WeixinPayAccount paymentAccount) { + protected final String payResponse; + + public AbstractPayRequest(String prePayId, String payResponse, WeixinPayAccount paymentAccount) { this.prePayId = prePayId; + this.payResponse = payResponse; this.paymentAccount = paymentAccount; this.weixinSignature = new WeixinPaymentSignature(paymentAccount.getPaySignKey()); + } @Override @@ -25,4 +29,10 @@ public abstract class AbstractPayRequest implements MchPayRequest { public WeixinPayAccount getPaymentAccount() { return this.paymentAccount; } + + + @Override + public String getResponseString() { + return payResponse; + } } \ No newline at end of file diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/JSAPIPayRequest.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/JSAPIPayRequest.java index 258167ce..f7398d4d 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/JSAPIPayRequest.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/JSAPIPayRequest.java @@ -25,8 +25,8 @@ import com.foxinmy.weixin4j.type.TradeType; */ public class JSAPIPayRequest extends AbstractPayRequest { - public JSAPIPayRequest(String prePayId, WeixinPayAccount payAccount) { - super(prePayId, payAccount); + public JSAPIPayRequest(PrePay prePay, WeixinPayAccount payAccount) { + super(prePay.getPrepayId(), prePay.getResponse(), payAccount); } @Override diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/MICROPayRequest.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/MICROPayRequest.java index 72ad9661..4fa6090c 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/MICROPayRequest.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/MICROPayRequest.java @@ -27,6 +27,8 @@ public class MICROPayRequest extends Order implements MchPayRequest { @JSONField(serialize = false) private WeixinPayAccount paymentAccount; + private String response; + protected MICROPayRequest() { // jaxb required } @@ -55,6 +57,16 @@ public class MICROPayRequest extends Order implements MchPayRequest { return null; } + + public void setResponse(String response) { + this.response = response; + } + + @Override + public String getResponseString() { + return response; + } + /** * 返回null,请不要尝试作为支付请求 */ diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/MchPayPackage.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/MchPayPackage.java index 4df383da..0295cb05 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/MchPayPackage.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/MchPayPackage.java @@ -108,6 +108,38 @@ public class MchPayPackage extends PayPackage { null, null, null, null); } + /** + * 微信支付 + * + * @param body + * 支付详情 必填 + * @param outTradeNo + * 商户侧订单号 必填 + * @param totalFee + * 支付金额(单位元) 必填 + * @param notifyUrl + * 支付回调URL 必填 + * @param createIp + * 发起支付的IP地址 必填 + * @param tradeType + * 支付类型 必填 + * @param openId + * 用户唯一标识 公众号JSAPI支付必填 + * @param authCode + * 支付授权码 刷卡MICROPAY支付必填 + * @param productId + * 商品ID 扫码NATIVE支付必填 + * @param attach + * 支付时附加信息 非必填 + */ + public MchPayPackage(String body, String outTradeNo, long totalFee, + String notifyUrl, String createIp, TradeType tradeType, + String openId, String authCode, String productId, String attach) { + this(body, null, outTradeNo, totalFee, notifyUrl, createIp, tradeType, + openId, authCode, productId, attach, null, null, null, null, + null); + } + /** * 完整参数 * @@ -147,12 +179,12 @@ public class MchPayPackage extends PayPackage { * 用户在子商户appid下的唯一标识 非必填 * openid和sub_openid可以选传其中之一,如果选择传sub_openid ,则必须传sub_appid */ - public MchPayPackage(String body, String detial, String outTradeNo, + public MchPayPackage(String body, String detail, String outTradeNo, double totalFee, CurrencyType feeType, String notifyUrl, String createIp, TradeType tradeType, String openId, String authCode, String productId, String attach, Date timeStart, Date timeExpire, String goodsTag, String limitPay, String subOpenId) { - super(body, detial, outTradeNo, totalFee, notifyUrl, createIp, attach, + super(body, detail, outTradeNo, totalFee, notifyUrl, createIp, attach, timeStart, timeExpire, goodsTag); this.tradeType = tradeType != null ? tradeType.name() : null; this.feeType = feeType == null ? CurrencyType.CNY.name() : feeType @@ -164,6 +196,58 @@ public class MchPayPackage extends PayPackage { this.subOpenId = subOpenId; } + /** + * 完整参数 + * + * @param body + * 商品描述 必填项 + * @param detail + * 商品名称明细列表 非必填项 + * @param outTradeNo + * 商户内部唯一订单号 必填项 + * @param totalFee + * 商品总额 单位元 必填项 + * @param notifyUrl + * 支付回调URL 必填项 + * @param createIp + * 订单生成的机器IP 必填项 + * @param tradeType + * 交易类型 必填项 + * @param openId + * 用户ID tradeType=JSAPI时必填 + * @param authCode + * 刷卡支付授权码 tradeType=MICROPAY时必填 + * @param productId + * 产品ID tradeType=NATIVE时必填 + * @param attach + * 附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据 非必填项 + * @param timeStart + * 订单生成时间,格式为yyyyMMddHHmmss 非必填项 + * @param timeExpire + * 订单失效时间,格式为yyyyMMddHHmmss;注意:最短失效时间间隔必须大于5分钟 非必填项 + * @param goodsTag + * 商品标记,代金券或立减优惠功能的参数 非必填项 + * @param limitPay + * 指定支付方式:no_credit--指定不能使用信用卡支付 非必填项 + * @param subOpenId + * 用户在子商户appid下的唯一标识 非必填 + * openid和sub_openid可以选传其中之一,如果选择传sub_openid ,则必须传sub_appid + */ + public MchPayPackage(String body, String detail, String outTradeNo, + long totalFee, String notifyUrl, String createIp, + TradeType tradeType, String openId, String authCode, + String productId, String attach, Date timeStart, Date timeExpire, + String goodsTag, String limitPay, String subOpenId) { + super(body, detail, outTradeNo, totalFee, notifyUrl, createIp, attach, + timeStart, timeExpire, goodsTag); + this.tradeType = tradeType.name(); + this.openId = openId; + this.authCode = authCode; + this.productId = productId; + this.limitPay = limitPay; + this.subOpenId = subOpenId; + } + public String getTradeType() { return tradeType; } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/MchPayRequest.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/MchPayRequest.java index 1feda2b4..5e2f2292 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/MchPayRequest.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/MchPayRequest.java @@ -52,4 +52,10 @@ public interface MchPayRequest { * @return */ public PayRequest toRequestObject(); + + /** + * 支付请求返回的结果 + * @return + */ + public String getResponseString(); } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/NATIVEPayRequest.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/NATIVEPayRequest.java index 3eb7809c..ddc88150 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/NATIVEPayRequest.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/NATIVEPayRequest.java @@ -20,9 +20,9 @@ public class NATIVEPayRequest extends AbstractPayRequest { private final String codeUrl; - public NATIVEPayRequest(String prePayId, String codeUrl, + public NATIVEPayRequest(PrePay prePay, String codeUrl, WeixinPayAccount payAccount) { - super(prePayId, payAccount); + super(prePay.getPrepayId(), prePay.getResponse(), payAccount); this.codeUrl = codeUrl; } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/Order.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/Order.java index f6662181..d31dc08b 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/Order.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/Order.java @@ -69,7 +69,7 @@ public class Order extends MerchantTradeResult { /** * 现金支付货币类型,符合 ISO 4217 标准的三位字母代码,默认人民币:CNY * - * @see com.foxinmy.weixin4j.mp.type.CurrencyType + * @see com.foxinmy.weixin4j.type.CurrencyType */ @XmlElement(name = "cash_fee_type") @JSONField(name = "cash_fee_type") diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/PrePay.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/PrePay.java index 55c8c823..23b7e63d 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/PrePay.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/PrePay.java @@ -40,6 +40,8 @@ public class PrePay extends MerchantResult { @XmlElement(name = "code_url") private String codeUrl; + private String response; + protected PrePay() { // jaxb required } @@ -72,6 +74,14 @@ public class PrePay extends MerchantResult { this.codeUrl = codeUrl; } + public String getResponse() { + return response; + } + + public void setResponse(String response) { + this.response = response; + } + @Override public String toString() { return "PrePay [tradeType=" + tradeType + ", prepayId=" + prepayId diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/Redpacket.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/Redpacket.java index e20aa563..ab060b02 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/Redpacket.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/Redpacket.java @@ -138,6 +138,43 @@ public class Redpacket extends MerchantResult { this.amtType = totalNum > 1 ? "ALL_RAND" : null; } + /** + * 红包 + * + * @param outTradeNo + * 商户侧一天内不可重复的订单号 接口根据商户订单号支持重入 如出现超时可再调用 必填 + * @param sendName + * 红包发送者名称 必填 + * @param openId + * 接受收红包的用户的openid 必填 + * @param totalAmount + * 付款金额 单位为分,自动格式化为分 必填 + * @param totalNum + * 红包发放总人数 大于1视为裂变红包 必填 + * @param wishing + * 红包祝福语 必填 + * @param clientIp + * Ip地址 必填 + * @param actName + * 活动名称 必填 + * @param remark + * 备注 必填 + */ + public Redpacket(String outTradeNo, String sendName, String openId, + int totalAmount, int totalNum, String wishing, String clientIp, + String actName, String remark) { + this.outTradeNo = outTradeNo; + this.sendName = sendName; + this.openId = openId; + this.totalNum = totalNum; + this.wishing = wishing; + this.clientIp = clientIp; + this.actName = actName; + this.remark = remark; + this.totalAmount = totalAmount; + this.amtType = totalNum > 1 ? "ALL_RAND" : null; + } + public String getOutTradeNo() { return outTradeNo; } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/WAPPayRequest.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/WAPPayRequest.java index 754fe66b..7c851c84 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/WAPPayRequest.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/WAPPayRequest.java @@ -22,8 +22,8 @@ import com.foxinmy.weixin4j.util.URLEncodingUtil; */ public class WAPPayRequest extends AbstractPayRequest { - public WAPPayRequest(String prePayId, WeixinPayAccount payAccount) { - super(prePayId, payAccount); + public WAPPayRequest(PrePay prePay, WeixinPayAccount payAccount) { + super(prePay.getPrepayId(),prePay.getResponse(), payAccount); } @Override diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/WeixinPaymentSignature.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/WeixinPaymentSignature.java index 9d32ef29..4bcbc260 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/WeixinPaymentSignature.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/sign/WeixinPaymentSignature.java @@ -1,36 +1,60 @@ package com.foxinmy.weixin4j.sign; +import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.type.SignType; import com.foxinmy.weixin4j.util.DigestUtil; +import com.foxinmy.weixin4j.xml.XmlStream; + +import java.util.Map; /** * 微信支付签名实现 * - * @className WeixinPaymentSignature * @author jinyu(foxinmy@gmail.com) + * @className WeixinPaymentSignature * @date 2016年3月26日 - * @since JDK 1.6 * @see 支付签名说明 + * href="https://pay.weixin.qq.com/wiki/doc/api/external/jsapi.php?chapter=4_3">支付签名说明 + * @since JDK 1.6 */ public class WeixinPaymentSignature extends AbstractWeixinSignature { - /** - * 支付密钥 - */ - private final String paySignKey; - public WeixinPaymentSignature(String paySignKey) { - this.paySignKey = paySignKey; - } + /** + * 支付密钥 + */ + private final String paySignKey; + + public WeixinPaymentSignature(String paySignKey) { + this.paySignKey = paySignKey; + } + + @Override + public SignType getSignType() { + return SignType.MD5; + } + + @Override + public String sign(Object obj) { + StringBuilder sb = join(obj).append("&key=").append(paySignKey); + return DigestUtil.MD5(sb.toString()).toUpperCase(); + } + + + public boolean validatePaySign(WeixinResponse weixinResponse) { + return this.validatePaySign(weixinResponse.getAsString()); + + } + + public boolean validatePaySign(String xmlResult) { + return this.validatePaySign(XmlStream.xml2map(xmlResult)); + } + + public boolean validatePaySign(Map map) { + String sign1 = map.get("sign"); + map.remove("sign"); + String sign2 = this.sign(map); + return sign1.equals(sign2); + } - @Override - public SignType getSignType() { - return SignType.MD5; - } - @Override - public String sign(Object obj) { - StringBuilder sb = join(obj).append("&key=").append(paySignKey); - return DigestUtil.MD5(sb.toString()).toUpperCase(); - } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/FileUtil.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/FileUtil.java index 0ccece44..e1f3a3ff 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/FileUtil.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/FileUtil.java @@ -11,152 +11,159 @@ import java.util.Map.Entry; /** * 文件工具类 - * - * @className FileUtil + * * @author jinyu(foxinmy@gmail.com) + * @className FileUtil * @date 2014年11月21日 - * @since JDK 1.6 * @see + * @since JDK 1.6 */ public class FileUtil { - private final static Map FILE_TYPE_MAP = new HashMap(); + private final static Map FILE_TYPE_MAP = new HashMap(); - static { - FILE_TYPE_MAP.put("ffd8ffe000104a464946", "jpg"); - FILE_TYPE_MAP.put("89504e470d0a1a0a0000", "png"); - FILE_TYPE_MAP.put("47494638396126026f01", "gif"); - FILE_TYPE_MAP.put("49492a00227105008037", "tif"); - FILE_TYPE_MAP.put("424d228c010000000000", "bmp"); // 16色位图(bmp) - FILE_TYPE_MAP.put("424d8240090000000000", "bmp"); // 24位位图(bmp) - FILE_TYPE_MAP.put("424d8e1b030000000000", "bmp"); // 256色位图(bmp) + static { + FILE_TYPE_MAP.put("ffd8ffe000104a464946", "jpg"); + FILE_TYPE_MAP.put("89504e470d0a1a0a0000", "png"); + FILE_TYPE_MAP.put("47494638396126026f01", "gif"); + FILE_TYPE_MAP.put("49492a00227105008037", "tif"); + FILE_TYPE_MAP.put("424d228c010000000000", "bmp"); // 16色位图(bmp) + FILE_TYPE_MAP.put("424d8240090000000000", "bmp"); // 24位位图(bmp) + FILE_TYPE_MAP.put("424d8e1b030000000000", "bmp"); // 256色位图(bmp) - FILE_TYPE_MAP.put("49443303000000002176", "mp3"); - FILE_TYPE_MAP.put("52494646", "wav"); - FILE_TYPE_MAP.put("00005741", "wav"); - FILE_TYPE_MAP.put("2321414d", "amr"); - FILE_TYPE_MAP.put("520a3c91", "amr"); - - FILE_TYPE_MAP.put("2e524d46000000120001", "rmvb"); // rmvb、rm - FILE_TYPE_MAP.put("464c5601050000000900", "flv"); // flv、f4v - FILE_TYPE_MAP.put("667479706d70", "mp4"); - FILE_TYPE_MAP.put("667479706973", "mp4"); - FILE_TYPE_MAP.put("000001ba210001000180", "mpg"); - FILE_TYPE_MAP.put("3026b2758e66cf11a6d9", "wmv"); // wmv、asf - FILE_TYPE_MAP.put("52494646d07d60074156", "avi"); + FILE_TYPE_MAP.put("49443303000000002176", "mp3"); + FILE_TYPE_MAP.put("52494646", "wav"); + FILE_TYPE_MAP.put("00005741", "wav"); + FILE_TYPE_MAP.put("2321414d", "amr"); + FILE_TYPE_MAP.put("520a3c91", "amr"); - FILE_TYPE_MAP.put("41433130313500000000", "dwg"); - FILE_TYPE_MAP.put("3c21444f435459504520", "html"); - FILE_TYPE_MAP.put("3c21646f637479706520", "htm"); - FILE_TYPE_MAP.put("48544d4c207b0d0a0942", "css"); - FILE_TYPE_MAP.put("696b2e71623d696b2e71", "js"); - FILE_TYPE_MAP.put("7b5c727466315c616e73", "rtf"); - FILE_TYPE_MAP.put("38425053000100000000", "psd"); - FILE_TYPE_MAP.put("46726f6d3a203d3f6762", "eml"); - FILE_TYPE_MAP.put("d0cf11e0a1b11ae10000", "doc"); // MS Excel、Word、Msi - FILE_TYPE_MAP.put("d0cf11e0a1b11ae10000", "vsd"); - FILE_TYPE_MAP.put("5374616E64617264204A", "mdb"); - FILE_TYPE_MAP.put("255044462d312e350d0a", "pdf"); - FILE_TYPE_MAP.put("4d546864000000060001", "mid"); - FILE_TYPE_MAP.put("504b0304140000000800", "zip"); - FILE_TYPE_MAP.put("526172211a0700cf9073", "rar"); - FILE_TYPE_MAP.put("235468697320636f6e66", "ini"); - FILE_TYPE_MAP.put("504b03040a0000000000", "jar"); - FILE_TYPE_MAP.put("4d5a9000030000000400", "exe"); - FILE_TYPE_MAP.put("3c25402070616765206c", "jsp"); - FILE_TYPE_MAP.put("4d616e69666573742d56", "mf"); - FILE_TYPE_MAP.put("3c3f786d6c2076657273", "xml"); - FILE_TYPE_MAP.put("494e5345525420494e54", "sql"); - FILE_TYPE_MAP.put("7061636b616765207765", "java"); - FILE_TYPE_MAP.put("406563686f206f66660d", "bat"); - FILE_TYPE_MAP.put("1f8b0800000000000000", "gz"); - FILE_TYPE_MAP.put("6c6f67346a2e726f6f74", "properties"); - FILE_TYPE_MAP.put("cafebabe0000002e0041", "class"); - FILE_TYPE_MAP.put("49545346030000006000", "chm"); - FILE_TYPE_MAP.put("04000000010000001300", "mxp"); - FILE_TYPE_MAP.put("504b0304140006000800", "docx"); - FILE_TYPE_MAP.put("d0cf11e0a1b11ae10000", "wps");// WPS(wps、et、dps) - FILE_TYPE_MAP.put("6431303a637265617465", "torrent"); - FILE_TYPE_MAP.put("6D6F6F76", "mov"); - FILE_TYPE_MAP.put("FF575043", "wpd"); - FILE_TYPE_MAP.put("CFAD12FEC5FD746F", "dbx"); - FILE_TYPE_MAP.put("2142444E", "pst"); - FILE_TYPE_MAP.put("AC9EBD8F", "qdf"); - FILE_TYPE_MAP.put("E3828596", "pwl"); - FILE_TYPE_MAP.put("2E7261FD", "ram"); - } + FILE_TYPE_MAP.put("2e524d46000000120001", "rmvb"); // rmvb、rm + FILE_TYPE_MAP.put("464c5601050000000900", "flv"); // flv、f4v + FILE_TYPE_MAP.put("667479706d70", "mp4"); + FILE_TYPE_MAP.put("667479706973", "mp4"); + FILE_TYPE_MAP.put("000001ba210001000180", "mpg"); + FILE_TYPE_MAP.put("3026b2758e66cf11a6d9", "wmv"); // wmv、asf + FILE_TYPE_MAP.put("52494646d07d60074156", "avi"); - private static String bytesToHexString(byte[] src) { - StringBuilder stringBuilder = new StringBuilder(); - for (int i = 0; i < src.length; i++) { - int v = src[i] & 0xFF; - String hv = Integer.toHexString(v); - if (hv.length() < 2) { - stringBuilder.append(0); - } - stringBuilder.append(hv); - } - return stringBuilder.toString(); - } + FILE_TYPE_MAP.put("41433130313500000000", "dwg"); + FILE_TYPE_MAP.put("3c21444f435459504520", "html"); + FILE_TYPE_MAP.put("3c21646f637479706520", "htm"); + FILE_TYPE_MAP.put("48544d4c207b0d0a0942", "css"); + FILE_TYPE_MAP.put("696b2e71623d696b2e71", "js"); + FILE_TYPE_MAP.put("7b5c727466315c616e73", "rtf"); + FILE_TYPE_MAP.put("38425053000100000000", "psd"); + FILE_TYPE_MAP.put("46726f6d3a203d3f6762", "eml"); + FILE_TYPE_MAP.put("d0cf11e0a1b11ae10000", "doc"); // MS Excel、Word、Msi + FILE_TYPE_MAP.put("d0cf11e0a1b11ae10000", "vsd"); + FILE_TYPE_MAP.put("5374616E64617264204A", "mdb"); + FILE_TYPE_MAP.put("255044462d312e350d0a", "pdf"); + FILE_TYPE_MAP.put("4d546864000000060001", "mid"); + FILE_TYPE_MAP.put("504b0304140000000800", "zip"); + FILE_TYPE_MAP.put("526172211a0700cf9073", "rar"); + FILE_TYPE_MAP.put("235468697320636f6e66", "ini"); + FILE_TYPE_MAP.put("504b03040a0000000000", "jar"); + FILE_TYPE_MAP.put("4d5a9000030000000400", "exe"); + FILE_TYPE_MAP.put("3c25402070616765206c", "jsp"); + FILE_TYPE_MAP.put("4d616e69666573742d56", "mf"); + FILE_TYPE_MAP.put("3c3f786d6c2076657273", "xml"); + FILE_TYPE_MAP.put("494e5345525420494e54", "sql"); + FILE_TYPE_MAP.put("7061636b616765207765", "java"); + FILE_TYPE_MAP.put("406563686f206f66660d", "bat"); + FILE_TYPE_MAP.put("1f8b0800000000000000", "gz"); + FILE_TYPE_MAP.put("6c6f67346a2e726f6f74", "properties"); + FILE_TYPE_MAP.put("cafebabe0000002e0041", "class"); + FILE_TYPE_MAP.put("49545346030000006000", "chm"); + FILE_TYPE_MAP.put("04000000010000001300", "mxp"); + FILE_TYPE_MAP.put("504b0304140006000800", "docx"); + FILE_TYPE_MAP.put("d0cf11e0a1b11ae10000", "wps");// WPS(wps、et、dps) + FILE_TYPE_MAP.put("6431303a637265617465", "torrent"); + FILE_TYPE_MAP.put("6D6F6F76", "mov"); + FILE_TYPE_MAP.put("FF575043", "wpd"); + FILE_TYPE_MAP.put("CFAD12FEC5FD746F", "dbx"); + FILE_TYPE_MAP.put("2142444E", "pst"); + FILE_TYPE_MAP.put("AC9EBD8F", "qdf"); + FILE_TYPE_MAP.put("E3828596", "pwl"); + FILE_TYPE_MAP.put("2E7261FD", "ram"); + } - /** - * 获取文件类型 - * - * @param is - * @return - */ - public static String getFileType(InputStream is) { - String fileType = "file"; - try { - byte[] b = new byte[10]; - int t = is.read(b, 0, b.length); - if (t > 0) { - String fileCode = bytesToHexString(b).toLowerCase(); - for (Entry entry : FILE_TYPE_MAP.entrySet()) { - String key = entry.getKey().toLowerCase(); - if (key.startsWith(fileCode) || fileCode.startsWith(key) - || key.endsWith(fileCode) || fileCode.endsWith(key)) { - fileType = entry.getValue(); - break; - } - } - } - } catch (IOException e) { - ; - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException ignore) { - ; - } - } - } - return fileType; - } + private static String bytesToHexString(byte[] src) { + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < src.length; i++) { + int v = src[i] & 0xFF; + String hv = Integer.toHexString(v); + if (hv.length() < 2) { + stringBuilder.append(0); + } + stringBuilder.append(hv); + } + return stringBuilder.toString(); + } - /** - * 获取文件后缀 - * - * @param fileName - * @return - */ - public static String getFileExtension(String fileName) { - int extensionPos = fileName.lastIndexOf("."); - if (extensionPos < 0) { - return ""; - } - int lastUnixPos = fileName.lastIndexOf("/"); - int lastWindowsPos = fileName.lastIndexOf("\\"); - int lastSeparator = Math.max(lastUnixPos, lastWindowsPos); - return lastSeparator > extensionPos ? "" : fileName - .substring(extensionPos + 1); - } + /** + * 获取文件类型 + */ + public static String getFileType(InputStream is) { + String fileType = "file"; + try { + byte[] b = new byte[10]; + int t = is.read(b, 0, b.length); + if (t > 0) { + String fileCode = bytesToHexString(b).toLowerCase(); + for (Entry entry : FILE_TYPE_MAP.entrySet()) { + String key = entry.getKey().toLowerCase(); + if (key.startsWith(fileCode) || fileCode.startsWith(key) || key.endsWith(fileCode) || fileCode.endsWith(key)) { + fileType = entry.getValue(); + break; + } + } + } + } catch (IOException e) { + ; + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException ignore) { + ; + } + } + } + return fileType; + } - public static void main(String[] args) throws IOException { - InputStream is = new FileInputStream(new File( - "/Users/jy/Downloads/test.mp4")); - System.err.println(getFileType(is)); - System.err.println(URLConnection.guessContentTypeFromStream(is)); - } + /** + * 获取文件后缀 + */ + public static String getFileExtension(String fileName) { + int extensionPos = fileName.lastIndexOf("."); + if (extensionPos < 0) { + return ""; + } + int lastUnixPos = fileName.lastIndexOf("/"); + int lastWindowsPos = fileName.lastIndexOf("\\"); + int lastSeparator = Math.max(lastUnixPos, lastWindowsPos); + return lastSeparator > extensionPos ? "" : fileName.substring(extensionPos + 1); + } + + /** + * 删除文件 + * @param filePath + * @return + */ + public static boolean deleteFile(String filePath) { + File file = new File(filePath); + if (!file.exists()) { + return true; + } + if (file.isFile()) { + return file.delete(); + } + return false; + } + + public static void main(String[] args) throws IOException { + InputStream is = new FileInputStream(new File("/Users/jy/Downloads/test.mp4")); + System.err.println(getFileType(is)); + System.err.println(URLConnection.guessContentTypeFromStream(is)); + } } \ No newline at end of file diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/IOUtil.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/IOUtil.java index b05cddc2..6651f62f 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/IOUtil.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/IOUtil.java @@ -1,6 +1,7 @@ package com.foxinmy.weixin4j.util; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -11,82 +12,84 @@ import java.nio.charset.Charset; /** * IOUtil - * - * @className IOUtil + * * @author jinyu(foxinmy@gmail.com) + * @className IOUtil * @date 2014年9月22日 - * @since JDK 1.6 * @see org.apache.commons.io.IOUtils + * @since JDK 1.6 */ public class IOUtil { - private static final int EOF = -1; - private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; + private static final int EOF = -1; + private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; - public static byte[] toByteArray(Reader input) throws IOException { - return toByteArray(input, Charset.defaultCharset()); - } + public static byte[] toByteArray(Reader input) throws IOException { + return toByteArray(input, Charset.defaultCharset()); + } - public static byte[] toByteArray(Reader input, Charset encoding) - throws IOException { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - copy(input, output, encoding); - return output.toByteArray(); - } + public static byte[] toByteArray(Reader input, Charset encoding) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + copy(input, output, encoding); + return output.toByteArray(); + } - public static void copy(Reader input, OutputStream output, Charset encoding) - throws IOException { - OutputStreamWriter out = new OutputStreamWriter(output, encoding); - copyLarge(input, out, new char[DEFAULT_BUFFER_SIZE]); - out.flush(); - } + public static void copy(Reader input, OutputStream output, Charset encoding) throws IOException { + OutputStreamWriter out = new OutputStreamWriter(output, encoding); + copyLarge(input, out, new char[DEFAULT_BUFFER_SIZE]); + out.flush(); + } - public static int copy(InputStream input, OutputStream output) - throws IOException { - long count = copyLarge(input, output); - if (count > Integer.MAX_VALUE) { - return -1; - } - return (int) count; - } + public static int copy(InputStream input, OutputStream output) throws IOException { + long count = copyLarge(input, output); + if (count > Integer.MAX_VALUE) { + return -1; + } + return (int) count; + } - private static long copyLarge(InputStream input, OutputStream output) - throws IOException { - byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; - long count = 0; - int n = 0; - while (-1 != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } + private static long copyLarge(InputStream input, OutputStream output) throws IOException { + byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; + long count = 0; + int n = 0; + while (-1 != (n = input.read(buffer))) { + output.write(buffer, 0, n); + count += n; + } + return count; + } - public static byte[] toByteArray(InputStream input) throws IOException { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - copyLarge(input, output, new byte[DEFAULT_BUFFER_SIZE]); - return output.toByteArray(); - } + public static byte[] toByteArray(InputStream input) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + copyLarge(input, output, new byte[DEFAULT_BUFFER_SIZE]); + return output.toByteArray(); + } - private static long copyLarge(InputStream input, OutputStream output, - byte[] buffer) throws IOException { - long count = 0; - int n = 0; - while (EOF != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } + private static long copyLarge(InputStream input, OutputStream output, byte[] buffer) throws IOException { + long count = 0; + int n = 0; + while (EOF != (n = input.read(buffer))) { + output.write(buffer, 0, n); + count += n; + } + return count; + } - private static long copyLarge(Reader input, Writer output, char[] buffer) - throws IOException { - long count = 0; - int n = 0; - while (EOF != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } + private static long copyLarge(Reader input, Writer output, char[] buffer) throws IOException { + long count = 0; + int n = 0; + while (EOF != (n = input.read(buffer))) { + output.write(buffer, 0, n); + count += n; + } + return count; + } + + public static void close(Closeable stream) { + try { + stream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/WeixinErrorUtil.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/WeixinErrorUtil.java index 80e49f10..6658cf27 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/WeixinErrorUtil.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/WeixinErrorUtil.java @@ -16,21 +16,23 @@ import com.foxinmy.weixin4j.http.weixin.WeixinResponse; /** * 接口调用错误获取 - * + * + * @author jy * @className WeixinErrorUtil * @author jinyu(foxinmy@gmail.com) * @date 2015年5月12日 - * @since JDK 1.6 * @see + * @since JDK 1.6 */ public final class WeixinErrorUtil { - private static byte[] errorXmlByteArray; + + private static byte[] errorXmlByteArray; private final static Map errorCacheMap; + static { errorCacheMap = new ConcurrentHashMap(); try { - errorXmlByteArray = IOUtil.toByteArray(WeixinResponse.class - .getResourceAsStream("error.xml")); + errorXmlByteArray = IOUtil.toByteArray(WeixinResponse.class.getResourceAsStream("error.xml")); } catch (IOException e) { ; } @@ -44,26 +46,23 @@ public final class WeixinErrorUtil { this.code = code; } - private String text; + private String text; private boolean codeElement; private boolean textElement; private boolean findElement; @Override - public void startElement(String uri, String localName, String qName, - Attributes attributes) throws SAXException { + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { codeElement = qName.equalsIgnoreCase("code"); textElement = qName.equalsIgnoreCase("text"); } @Override - public void endElement(String uri, String localName, String qName) - throws SAXException { + public void endElement(String uri, String localName, String qName) throws SAXException { } @Override - public void characters(char[] ch, int start, int length) - throws SAXException { + public void characters(char[] ch, int start, int length) throws SAXException { String _text = new String(ch, start, length); if (codeElement && _text.equalsIgnoreCase(code)) { findElement = true; @@ -88,8 +87,7 @@ public final class WeixinErrorUtil { try { XMLReader xmlReader = XMLReaderFactory.createXMLReader(); xmlReader.setContentHandler(textHandler); - xmlReader.parse(new InputSource(new ByteArrayInputStream( - errorXmlByteArray))); + xmlReader.parse(new InputSource(new ByteArrayInputStream(errorXmlByteArray))); text = textHandler.getText(); errorCacheMap.put(code, text); } catch (IOException e) { @@ -102,9 +100,10 @@ public final class WeixinErrorUtil { return text; } + public static void main(String[] args) { - System.out.println(getText("40001")); - System.out.println(getText("40001")); + System.out.println(getText("30002")); + System.out.println(getText("30002")); System.out.println(getText("1234")); } } diff --git a/weixin4j-mp/pom.xml b/weixin4j-mp/pom.xml index 07ea2246..37a3f242 100644 --- a/weixin4j-mp/pom.xml +++ b/weixin4j-mp/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.7.3 + 1.7.3-SNAPSHOT weixin4j-mp weixin4j-mp diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java index 154cdeb4..a10d6861 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java @@ -306,7 +306,8 @@ public class MassApi extends MpApi { * @see 删除群发 * @see {@link #massByTagId(Tuple, int)} - * @see {@link #massByOpenIds(Tuple, String...) + * @see {@link #massByOpenIds(Tuple, String...) + */ public ApiResult deleteMassNews(String msgid) throws WeixinException { JSONObject obj = new JSONObject(); diff --git a/weixin4j-qy/pom.xml b/weixin4j-qy/pom.xml index 9c16a356..893462bc 100644 --- a/weixin4j-qy/pom.xml +++ b/weixin4j-qy/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.7.3 + 1.7.3-SNAPSHOT weixin4j-qy weixin4j-qy From 24c5076f0b419ca852c69feb1d62e8826c066b49 Mon Sep 17 00:00:00 2001 From: fengyapeng Date: Tue, 20 Dec 2016 10:34:52 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BC=9A=E5=91=98?= =?UTF-8?q?=E5=8D=A1=EF=BC=8C=E5=A2=9E=E5=8A=A0=E6=91=87=E4=B8=80=E6=91=87?= =?UTF-8?q?=E9=83=A8=E5=88=86=E8=AE=BE=E5=A4=87=E6=8E=A5=E5=8F=A3=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin4j/model/card/MemCardBonusRule.java | 118 ++++++ .../model/card/MemCardCustomField.java | 73 ++++ .../weixin4j/model/card/MemberCard.java | 384 ++++++++++++++++++ .../weixin4j/type/card/CardStatus.java | 36 ++ .../foxinmy/weixin4j/type/card/CardType.java | 7 +- .../weixin4j/type/card/FieldNameType.java | 42 ++ .../weixin4j/util/WeixinErrorUtil2.java | 112 +++++ .../weixin4j/mp/api/ShakeAroundApi.java | 275 +++++++++++++ .../foxinmy/weixin4j/mp/api/weixin.properties | 209 +++++----- .../weixin4j/mp/model/shakearound/Device.java | 158 +++++++ .../model/shakearound/DeviceAuditState.java | 84 ++++ .../mp/model/shakearound/ShakeUserInfo.java | 58 +++ .../foxinmy/weixin4j/mp/test/HelpTest.java | 35 ++ 13 files changed, 1491 insertions(+), 100 deletions(-) create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemCardBonusRule.java create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemCardCustomField.java create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberCard.java create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/CardStatus.java create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/FieldNameType.java create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/WeixinErrorUtil2.java create mode 100644 weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/ShakeAroundApi.java create mode 100644 weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/shakearound/Device.java create mode 100644 weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/shakearound/DeviceAuditState.java create mode 100644 weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/shakearound/ShakeUserInfo.java create mode 100644 weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/HelpTest.java diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemCardBonusRule.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemCardBonusRule.java new file mode 100644 index 00000000..7e13b99a --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemCardBonusRule.java @@ -0,0 +1,118 @@ +package com.foxinmy.weixin4j.model.card; + +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 会员卡积分规则 + * + * @auther: Feng Yapeng + * @since: 2016/12/15 11:43 + */ +public class MemCardBonusRule { + + /** + * 消费金额。以分为单位。 + */ + @JSONField(name = "cost_money_unit") + private int costMoneyUnit; + /** + * 对应增加的积分 + */ + @JSONField(name = "increase_bonus") + private int increaseBonus; + /** + * 用户单次可获取的积分上限。 + */ + @JSONField(name = "max_increase_bonus ") + private int maxIncreaseBonus; + /** + * 初始设置积分【可以理解为开卡积分】 + */ + @JSONField(name = "init_increase_bonus") + private int initIncreaseBonus; + /** + *每使用N 积分 + */ + @JSONField(name = "cost_bonus_unit") + private int costBonusUnit; + /** + * 抵扣多少分 + */ + @JSONField(name = "reduce_money") + private int reduceMoney; + /** + * 抵扣条件,满xx分(这里以分为单位)可用 + */ + @JSONField(name = "least_money_to_use_bonus") + private int leastMoneyToUseBonus; + /** + * + */ + @JSONField(name = "max_reduce_bonus") + private int maxReduceBonus; + + + public int getCostMoneyUnit() { + return costMoneyUnit; + } + + public void setCostMoneyUnit(int costMoneyUnit) { + this.costMoneyUnit = costMoneyUnit; + } + + public int getIncreaseBonus() { + return increaseBonus; + } + + public void setIncreaseBonus(int increaseBonus) { + this.increaseBonus = increaseBonus; + } + + public int getMaxIncreaseBonus() { + return maxIncreaseBonus; + } + + public void setMaxIncreaseBonus(int maxIncreaseBonus) { + this.maxIncreaseBonus = maxIncreaseBonus; + } + + public int getInitIncreaseBonus() { + return initIncreaseBonus; + } + + public void setInitIncreaseBonus(int initIncreaseBonus) { + this.initIncreaseBonus = initIncreaseBonus; + } + + public int getCostBonusUnit() { + return costBonusUnit; + } + + public void setCostBonusUnit(int costBonusUnit) { + this.costBonusUnit = costBonusUnit; + } + + public int getReduceMoney() { + return reduceMoney; + } + + public void setReduceMoney(int reduceMoney) { + this.reduceMoney = reduceMoney; + } + + public int getLeastMoneyToUseBonus() { + return leastMoneyToUseBonus; + } + + public void setLeastMoneyToUseBonus(int leastMoneyToUseBonus) { + this.leastMoneyToUseBonus = leastMoneyToUseBonus; + } + + public int getMaxReduceBonus() { + return maxReduceBonus; + } + + public void setMaxReduceBonus(int maxReduceBonus) { + this.maxReduceBonus = maxReduceBonus; + } +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemCardCustomField.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemCardCustomField.java new file mode 100644 index 00000000..0e8388e0 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemCardCustomField.java @@ -0,0 +1,73 @@ +package com.foxinmy.weixin4j.model.card; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.type.card.FieldNameType; + +/** + * 会员卡自定义类型 + * + * @auther: Feng Yapeng + * @since: 2016/12/15 10:49 + */ +public class MemCardCustomField { + + /** + *会员信息类目半自定义名称,当开发者变更这类类目信息的value值时,可以选择触发系统模板消息通知用户。 + */ + @JSONField(name = "name_type") + private FieldNameType nameType; + + /** + * 会员信息类目自定义名称,当开发者变更这类类目信息的value值时, 不会触发系统模板消息通知用户 + */ + private String name; + /** + * 点击类目跳转外链url + */ + private String url; + /** + * s + */ + private String tips; + + public MemCardCustomField(FieldNameType fieldNameType, String url) { + this.nameType = fieldNameType; + this.url = url; + } + + public MemCardCustomField(FieldNameType fieldNameType, String name, String url) { + this.nameType = fieldNameType; + this.name = name; + this.url = url; + } + + public MemCardCustomField(String name, String url, String tips) { + this.name = name; + this.url = url; + this.tips = tips; + } + + public FieldNameType getNameType() { + return nameType; + } + + public void setNameType(FieldNameType nameType) { + this.nameType = nameType; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberCard.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberCard.java new file mode 100644 index 00000000..2cb211fb --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberCard.java @@ -0,0 +1,384 @@ +package com.foxinmy.weixin4j.model.card; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.type.card.CardType; +import com.foxinmy.weixin4j.type.card.FieldNameType; + +/** + * 会员卡 + * @auther: Feng Yapeng + * @since: 2016/12/15 10:09 + */ +public class MemberCard extends CardCoupon { + + /** + * 会员卡背景图 [商家自定义会员卡背景图,须先调用上传图片接口将背景图上传至CDN,否则报错, + * 卡面设计请遵循微信会员卡自定义背景设计规范 ,像素大小控制在1000像素*600像素以下] + */ + @JSONField(name = "background_pic_url") + private String backgroundPicUrl; + + /** + * 会员卡特权说明。 + */ + @JSONField(name = "prerogative") + private String prerogative; + /** + * 用户领取会员卡后系统自动将其激活,无需调用激活接口,详情见自动激活。 + */ + @JSONField(name = "auto_activate") + private boolean autoActivate; + /** + * 设置为true时会员卡支持一键开卡,不允许同时传入activate_url字段,否则设置wx_activate失效。 + */ + @JSONField(name = "wx_activate") + private boolean wxActivate; + /** + * 激活会员卡的url。 + */ + @JSONField(name = "activate_url") + private String activateUrl; + + /** + * 显示积分 【true:积分相关字段均为必填】 + */ + @JSONField(name = "supply_bonus") + private boolean supplyBonus; + /** + * 设置跳转外链查看积分详情。仅适用于积分无法通过激活接口同步的情况下使用该字段 + */ + @JSONField(name = "bonus_url") + private String bonusUrl; + /** + * 显示余额 + */ + @JSONField(name = "supply_balance") + private String supplyBalance; + /** + * 设置跳转外链查看余额详情。仅适用于余额无法通过激活接口同步的情况下使用该字段。 + */ + @JSONField(name = "balance_url") + private String balanceUrl; + + /** + * 自定义会员信息类目 + */ + @JSONField(name = "custom_field1") + private MemCardCustomField customField1; + /** + * 自定义会员信息类目 + */ + @JSONField(name = "custom_field2") + private MemCardCustomField customField2; + /** + * 自定义会员信息类目 + */ + @JSONField(name = "custom_field3") + private MemCardCustomField customField3; + + /** + * 积分规则说明 + */ + @JSONField(name = "bonus_rules") + private String bonusRules; + /** + * 储值说明。 + */ + @JSONField(name = "balance_rules") + private String balanceRules; + /** + * 积分清零规则 + */ + @JSONField(name = "bonus_cleared") + private String bonusCleared; + /** + * 自定义会员信息类目,会员卡激活后显示 + */ + @JSONField(name = "custom_cell1") + private MemCardCustomField customCell1; + + /** + * 折扣【该会员卡享受的折扣优惠,填10就是九折。】 + */ + private int discount; + + @JSONField(name = "bonus_rule") + private MemCardBonusRule bonusRule; + + + /** + * 卡券 + * + * @param couponBaseInfo 基础信息 + */ + protected MemberCard(CouponBaseInfo couponBaseInfo, Builder builder) { + super(couponBaseInfo); + this.activateUrl = builder.activateUrl; + this.backgroundPicUrl = builder.backgroundPicUrl; + this.prerogative = builder.prerogative; + this.autoActivate = builder.autoActivate; + this.wxActivate = builder.wxActivate; + this.activateUrl = builder.activateUrl; + this.supplyBonus = builder.supplyBonus; + this.bonusUrl = builder.bonusUrl; + this.supplyBalance = builder.supplyBalance; + this.balanceUrl = builder.balanceUrl; + this.customField1 = builder.customField1; + this.customField2 = builder.customField2; + this.customField3 = builder.customField3; + this.bonusRules = builder.bonusRules; + this.balanceRules = builder.balanceRules; + this.bonusCleared = builder.bonusCleared; + this.customCell1 = builder.customCell1; + this.discount = builder.discount; + this.bonusRule = builder.bonusRule; + } + + @Override + public CardType getCardType() { + return CardType.MEMBER_CARD; + } + + public String getBackgroundPicUrl() { + return backgroundPicUrl; + } + + public String getPrerogative() { + return prerogative; + } + + public boolean isAutoActivate() { + return autoActivate; + } + + public boolean isWxActivate() { + return wxActivate; + } + + public String getActivateUrl() { + return activateUrl; + } + + public boolean isSupplyBonus() { + return supplyBonus; + } + + public String getBonusUrl() { + return bonusUrl; + } + + public String getSupplyBalance() { + return supplyBalance; + } + + public String getBalanceUrl() { + return balanceUrl; + } + + public MemCardCustomField getCustomField1() { + return customField1; + } + + public MemCardCustomField getCustomField2() { + return customField2; + } + + public MemCardCustomField getCustomField3() { + return customField3; + } + + public String getBonusRules() { + return bonusRules; + } + + public String getBalanceRules() { + return balanceRules; + } + + public String getBonusCleared() { + return bonusCleared; + } + + public MemCardCustomField getCustomCell1() { + return customCell1; + } + + public int getDiscount() { + return discount; + } + + public MemCardBonusRule getBonusRule() { + return bonusRule; + } + + + public static final class Builder { + + /** + * 会员卡背景图 [商家自定义会员卡背景图,须先调用上传图片接口将背景图上传至CDN,否则报错, + * 卡面设计请遵循微信会员卡自定义背景设计规范 ,像素大小控制在1000像素*600像素以下] + */ + private String backgroundPicUrl; + + /** + * 会员卡特权说明。 + */ + private String prerogative; + /** + * 用户领取会员卡后系统自动将其激活,无需调用激活接口,详情见自动激活。 + */ + private boolean autoActivate; + /** + * 设置为true时会员卡支持一键开卡,不允许同时传入activate_url字段,否则设置wx_activate失效。 + */ + private boolean wxActivate; + /** + * 激活会员卡的url。 + */ + private String activateUrl; + + /** + * 显示积分 【true:积分相关字段均为必填】 + */ + private boolean supplyBonus; + /** + * 设置跳转外链查看积分详情。仅适用于积分无法通过激活接口同步的情况下使用该字段 + */ + private String bonusUrl; + /** + * 显示余额 + */ + private String supplyBalance; + /** + * 设置跳转外链查看余额详情。仅适用于余额无法通过激活接口同步的情况下使用该字段。 + */ + private String balanceUrl; + /** + * 自定义会员信息类目 + */ + private MemCardCustomField customField1; + /** + * 自定义会员信息类目 + */ + private MemCardCustomField customField2; + /** + * 自定义会员信息类目 + */ + private MemCardCustomField customField3; + /** + * 积分规则说明 + */ + private String bonusRules; + /** + * 储值说明。 + */ + private String balanceRules; + /** + * 积分清零规则 + */ + private String bonusCleared; + /** + * 自定义会员信息类目,会员卡激活后显示 + */ + private MemCardCustomField customCell1; + /** + * 折扣【该会员卡享受的折扣优惠,填10就是九折。】 + */ + private int discount; + /** + * 积分规则 + */ + private MemCardBonusRule bonusRule; + + + public Builder setBackgroundPicUrl(String backgroundPicUrl) { + this.backgroundPicUrl = backgroundPicUrl; + return this; + } + + public Builder setPrerogative(String prerogative) { + this.prerogative = prerogative; + return this; + } + + public Builder setAutoActivate(boolean autoActivate) { + this.autoActivate = autoActivate; + return this; + } + + public Builder setWxActivate(boolean wxActivate) { + this.wxActivate = wxActivate; + return this; + } + + public Builder setActivateUrl(String activateUrl) { + this.activateUrl = activateUrl; + return this; + } + + public Builder setSupplyBonus(boolean supplyBonus) { + this.supplyBonus = supplyBonus; + return this; + } + + public Builder setBonusUrl(String bonusUrl) { + this.bonusUrl = bonusUrl; + return this; + } + + public Builder setSupplyBalance(String supplyBalance) { + this.supplyBalance = supplyBalance; + return this; + } + + public Builder setBalanceUrl(String balanceUrl) { + this.balanceUrl = balanceUrl; + return this; + } + + public Builder setCustomField1(FieldNameType type, String name, String url) { + this.customField1 = new MemCardCustomField(type, name, url); + return this; + } + + public Builder setCustomField2(FieldNameType type, String name, String url) { + this.customField2 = new MemCardCustomField(type, name, url); + return this; + } + + public Builder setCustomField3(FieldNameType type, String name, String url) { + this.customField3 = new MemCardCustomField(type, name, url); + return this; + } + + public Builder setBonusRules(String bonusRules) { + this.bonusRules = bonusRules; + return this; + } + + public Builder setBalanceRules(String balanceRules) { + this.balanceRules = balanceRules; + return this; + } + + public Builder setBonusCleared(String bonusCleared) { + this.bonusCleared = bonusCleared; + return this; + } + + public Builder setCustomCell1(String name, String url, String tips) { + this.customCell1 = new MemCardCustomField(name, url, tips); + return this; + } + + public Builder setDiscount(int discount) { + this.discount = discount; + return this; + } + + public Builder setBonusRule(MemCardBonusRule bonusRule) { + this.bonusRule = bonusRule; + return this; + } + } +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/CardStatus.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/CardStatus.java new file mode 100644 index 00000000..1e48bdca --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/CardStatus.java @@ -0,0 +1,36 @@ +package com.foxinmy.weixin4j.type.card; + +/** + * 会员卡的状态 + * + * @auther: Feng Yapeng + * @since: 2016/12/19 11:39 + */ +public enum CardStatus { + + /** + * 待审核; + */ + CARD_STATUS_NOT_VERIFY, + + /** + * 审核失败 + */ + CARD_STATUS_VERIFY_FAIL, + + /** + * 通过审核 + */ + CARD_STATUS_VERIFY_OK, + + /** + * 卡券被商户删除 + */ + CARD_STATUS_DELETE, + + /** + * 在公众平台投放过的卡券 + */ + CARD_STATUS_DISPATCH; + +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/CardType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/CardType.java index a32c2c11..f9354e7f 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/CardType.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/CardType.java @@ -29,5 +29,10 @@ public enum CardType { /** * 优惠券 */ - GENERAL_COUPON; + GENERAL_COUPON, + + /** + * 会员卡 + */ + MEMBER_CARD; } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/FieldNameType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/FieldNameType.java new file mode 100644 index 00000000..b1c11743 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/FieldNameType.java @@ -0,0 +1,42 @@ +package com.foxinmy.weixin4j.type.card; + +/** + * 会员信息类目半自定义名称 + * + * @auther: Feng Yapeng + * @since: 2016/12/15 10:37 + */ +public enum FieldNameType { + /** + * 等级 + */ + FIELD_NAME_TYPE_LEVEL, + /** + * 优惠券 + */ + FIELD_NAME_TYPE_COUPON, + /** + * 印花 + */ + FIELD_NAME_TYPE_STAMP, + /** + * 折扣 + */ + FIELD_NAME_TYPE_DISCOUNT, + /** + * 成就 + */ + FIELD_NAME_TYPE_ACHIEVEMEN, + /** + * 里程 + */ + FIELD_NAME_TYPE_MILEAGE, + /** + * 集点 + */ + FIELD_NAME_TYPE_SET_POINTS, + /** + * 次数 + */ + FIELD_NAME_TYPE_TIMS; +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/WeixinErrorUtil2.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/WeixinErrorUtil2.java new file mode 100644 index 00000000..3f0634ba --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/WeixinErrorUtil2.java @@ -0,0 +1,112 @@ +package com.foxinmy.weixin4j.util; + +import com.foxinmy.weixin4j.http.weixin.WeixinResponse; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; +import org.xml.sax.helpers.XMLReaderFactory; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 接口调用错误获取 + * + * @author fengyapeng + * @className WeixinErrorUtil2 + * @date + * @see + * @since JDK 1.6 + */ +public final class WeixinErrorUtil2 { + + private static byte[] errorXmlByteArray; + private final static Map errorCacheMap; + + static { + errorCacheMap = new ConcurrentHashMap(); + try { + errorXmlByteArray = IOUtil.toByteArray(WeixinResponse.class.getResourceAsStream("error.xml")); + XMLReader xmlReader = XMLReaderFactory.createXMLReader(); + ContentHandler textHandler = new ErrorTextHandler(errorCacheMap); + xmlReader.setContentHandler(textHandler); + xmlReader.parse(new InputSource(new ByteArrayInputStream(errorXmlByteArray))); + } catch (IOException e) { + ; + } catch (SAXException e) { + + } + } + + private static class ErrorTextHandler extends DefaultHandler { + + private Map errorCacheMap; + + public ErrorTextHandler(Map errorCacheMap) { + this.errorCacheMap = errorCacheMap; + } + + private String code; + private String text; + private boolean codeElement; + private boolean textElement; + private int isPair = 0; + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + codeElement = qName.equalsIgnoreCase("code"); + textElement = qName.equalsIgnoreCase("text"); + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + String _text = new String(ch, start, length); + if (codeElement) { + isPair++; + code = _text; + codeElement = false; + } + if (textElement) { + isPair++; + text = _text; + textElement = false; + } + if (isPair == 2) { + // 配对成功 + errorCacheMap.put(code, text); + isPair = 0; + code = null; + text = null; + } + } + } + + public static String getText(String code) throws RuntimeException { + return errorCacheMap.get(code); + } + + public static String getText(String code, String defaultMsg) throws RuntimeException { + String text = getText(code); + if (StringUtil.isNotBlank(text)) { + return text; + } + return defaultMsg; + } + + + public static void main(String[] args) { + System.out.println(getText("40001")); + System.out.println(getText("30002")); + System.out.println(getText("1234")); + } +} diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/ShakeAroundApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/ShakeAroundApi.java new file mode 100644 index 00000000..284ad1fe --- /dev/null +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/ShakeAroundApi.java @@ -0,0 +1,275 @@ +package com.foxinmy.weixin4j.mp.api; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.weixin.ApiResult; +import com.foxinmy.weixin4j.http.weixin.WeixinResponse; +import com.foxinmy.weixin4j.model.Token; +import com.foxinmy.weixin4j.model.paging.Pageable; +import com.foxinmy.weixin4j.model.paging.Pagedata; +import com.foxinmy.weixin4j.mp.model.shakearound.Device; +import com.foxinmy.weixin4j.mp.model.shakearound.DeviceAuditState; +import com.foxinmy.weixin4j.mp.model.shakearound.ShakeUserInfo; +import com.foxinmy.weixin4j.token.TokenManager; +import com.sun.javafx.binding.StringFormatter; + +import java.util.ArrayList; +import java.util.List; + +/** + * 摇一摇周边 + * + * @author fengyapeng + * @auther: Feng Yapeng feng27156@gmail.com + * @since: 2016 /10/12 21:13 + * @since 2016 -10-13 10:49:39 + */ +public class ShakeAroundApi extends MpApi { + + + private final TokenManager tokenManager; + + + /** + * Instantiates a new Shake around api. + * + * @param tokenManager the token manager + */ + public ShakeAroundApi(TokenManager tokenManager) { + this.tokenManager = tokenManager; + } + + /** + * 申请配置设备所需的UUID、Major、Minor。申请成功后返回批次ID,可用返回的批次ID通过“查询设备ID申请状态”接口查询目前申请的审核状态。 + * 若单次申请的设备ID数量小于500个,系统会进行快速审核;若单次申请的设备ID数量大于等 500个 ,会在三个工作日内完成审核。 + * 如果已审核通过,可用返回的批次ID通过“查询设备列表”接口拉取本次申请的设备ID。 通过接口申请的设备ID,需先配置页面,若未配置页面,则摇不出页面信息。 + * + * @param quantity the quantity 申请的设备ID的数量,单次新增设备超过500个,需走人工审核流程 + * @param applyReason the apply reason 申请理由,不超过100个汉字或200个英文字母 + * @param comment the comment 备注,不超过15个汉字或30个英文字母 + * @return the api result + * @throws WeixinException the weixin exception + * @author fengyapeng + * @see + * @since 2016 -10-12 21:21:47 + */ + public DeviceAuditState deviceApply(Integer quantity, String applyReason, String comment) throws WeixinException { + String device_apply_uri = getRequestUri("shake_around_device_apply"); + Token token = this.tokenManager.getCache(); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("quantity", quantity); + jsonObject.put("apply_reason", applyReason); + jsonObject.put("comment", comment); + WeixinResponse response = weixinExecutor.post(String.format(device_apply_uri, token.getAccessToken()), jsonObject.toJSONString()); + DeviceAuditState result = JSON.parseObject(response.getAsJson().getString("data"), DeviceAuditState.class); + result.setApplyTime(System.currentTimeMillis() / 1000); + result.setAuditTime(0); + return result; + } + + + /** + * 查询设备ID申请的审核状态。若单次申请的设备ID数量小于等于500个, + * 系统会进行快速审核;若单次申请的设备ID数量大于500个,则在三个工作日内完成审核。 + * + * @param applyId the apply id 批次ID,申请设备ID时所返回的批次ID + * @return the device audit state + * @throws WeixinException the weixin exception + * @author fengyapeng + * @see + * @since 2016 -10-12 21:57:04 + */ + public DeviceAuditState deviceQueryApplyStatus(int applyId) throws WeixinException { + String device_apply_status_uri = getRequestUri("shake_around_device_apply_status_uri"); + Token token = this.tokenManager.getCache(); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("apply_id", applyId); + WeixinResponse response = weixinExecutor + .post(String.format(device_apply_status_uri, token.getAccessToken()), jsonObject.toJSONString()); + DeviceAuditState result = JSON.parseObject(response.getAsJson().getString("data"), DeviceAuditState.class); + result.setApplyId(applyId); + return result; + } + + /** + * 查询已有的设备ID、UUID、Major、Minor、激活状态、备注信息、关联门店、关联页面等信息。 + * 查询指定设备的信息 + * + * @param device the device + * @return the list + * @throws WeixinException the weixin exception + * @author fengyapeng + * @since 2016 -10-13 10:11:34 + */ + public List deviceSearchDevices(List device) throws WeixinException { + String device_search_uri = getRequestUri("shake_around_device_search_uri"); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("type", 1); + jsonObject.put("device_identifiers", device); + WeixinResponse response = weixinExecutor + .post(String.format(device_search_uri, tokenManager.getAccessToken()), jsonObject.toJSONString()); + JSONObject json = response.getAsJson(); + String deviceStr = json.getJSONObject("data").getString("devices"); + return JSON.parseArray(deviceStr, Device.class); + } + + /** + * 查询已有的设备ID、UUID、Major、Minor、激活状态、备注信息、关联门店、关联页面等信息。 + * 按照分页信息查询设备 + * + * @return the list + * @throws WeixinException the weixin exception + * @author fengyapeng + * @since 2016 -10-13 10:11:34 + */ + public Pagedata deviceSearchDevices(int pageSize) throws WeixinException { + return this.deviceSearchDevices(0, pageSize); + } + + /** + * 查询已有的设备ID、UUID、Major、Minor、激活状态、备注信息、关联门店、关联页面等信息 + * 根据上次查询的最后的设备编号按照分页查询 + * + * @param lastDeviceId the last device id + * @param pageSize the page size + * @return list pagedata + * @throws WeixinException the weixin exception + * @author fengyapeng + * @since 2016 -10-13 10:52:20 + */ + public Pagedata deviceSearchDevices(int lastDeviceId, int pageSize) throws WeixinException { + String device_search_uri = getRequestUri("shake_around_device_search_uri"); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("type", 2); + jsonObject.put("last_seen", lastDeviceId); + if (pageSize > 50) { + pageSize = 50; + } + jsonObject.put("count", pageSize); + WeixinResponse response = weixinExecutor + .post(String.format(device_search_uri, tokenManager.getAccessToken()), jsonObject.toJSONString()); + JSONObject json = response.getAsJson(); + JSONObject data = json.getJSONObject("data"); + String deviceStr = data.getString("devices"); + List devices = JSON.parseArray(deviceStr, Device.class); + Pagedata pagedata = new Pagedata(null, data.getIntValue("total_count"), devices); + return pagedata; + } + + /** + * 查询已有的设备ID、UUID、Major、Minor、激活状态、备注信息、关联门店、关联页面等信息 + * 查询 设备Id 下的所有的设备 + * + * @param applyId the apply id + * @return the list + * @author fengyapeng + * @since 2016 -10-13 10:49:39 + */ + public List deviceSearchDevicesByApplyId(Integer applyId) throws WeixinException { + List devices = new ArrayList(); + Pagedata pagedata = this.deviceSearchDevicesByApplyId(applyId, 50); + devices = pagedata.getContent(); + for (int page = 50; page < pagedata.getTotalElements(); page = page + 50) { + List _devices = pagedata.getContent(); + pagedata = this.deviceSearchDevicesByApplyId(applyId, _devices.get(_devices.size() - 1).getDeviceId(), 50); + _devices = pagedata.getContent(); + devices.addAll(_devices); + } + return devices; + } + + + /** + * 查询已有的设备ID、UUID、Major、Minor、激活状态、备注信息、关联门店、关联页面等信息 + * 分页获取设备id下的前多少设备 + * + * @param applyId the apply id + * @return the list + * @author fengyapeng + * @since 2016 -10-13 10:49:39 + */ + public Pagedata deviceSearchDevicesByApplyId(Integer applyId, int pageSize) throws WeixinException { + return this.deviceSearchDevicesByApplyId(applyId, 0, pageSize); + } + + /** + * 查询已有的设备ID、UUID、Major、Minor、激活状态、备注信息、关联门店、关联页面等信息 + * 分页获取设备id下的根据上次查询的最后的设备编号前多少设备 + * + * @param applyId the apply id + * @return the list + * @author fengyapeng + * @since 2016 -10-13 10:49:39 + */ + public Pagedata deviceSearchDevicesByApplyId(Integer applyId, int lastDeviceId, int pageSize) throws WeixinException { + String device_search_uri = getRequestUri("shake_around_device_search_uri"); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("type", 3); + jsonObject.put("apply_id", applyId); + jsonObject.put("last_seen", lastDeviceId); + if (pageSize > 50) { + pageSize = 50; + } + jsonObject.put("count", pageSize); + WeixinResponse response = weixinExecutor + .post(String.format(device_search_uri, tokenManager.getAccessToken()), jsonObject.toJSONString()); + JSONObject json = response.getAsJson(); + JSONObject data = json.getJSONObject("data"); + String deviceStr = data.getString("devices"); + List devices = JSON.parseArray(deviceStr, Device.class); + Pagedata pagedata = new Pagedata(null, data.getIntValue("total_count"), devices); + return pagedata; + } + + + /** + * 编辑设备的备注信息。可用设备ID或完整的UUID、Major、Minor指定设备,二者选其一。 + * + * @param device the device + * @param comment the comment + * @return api result + * @author fengyapeng + * @since 2016 -10-13 14:33:06 + */ + public ApiResult deviceUpdateComment(Device device, String comment) throws WeixinException { + String device_update_uri = getRequestUri("shake_around_device_update_uri"); + JSONObject jsonObject = new JSONObject(); + JSONObject deviceJsonObj = new JSONObject(); + jsonObject.put("device_identifier", deviceJsonObj); + jsonObject.put("comment", comment); + if (device.getDeviceId() == null) { + deviceJsonObj.put("uuid", device.getUuid()); + deviceJsonObj.put("major", device.getMajor()); + deviceJsonObj.put("minor", device.getMinor()); + } else { + deviceJsonObj.put("device_id", device.getDeviceId()); + } + WeixinResponse weixinResponse = weixinExecutor + .post(String.format(device_update_uri, tokenManager.getAccessToken()), jsonObject.toJSONString()); + return weixinResponse.getAsResult(); + + } + + /** + * 获取设备信息,包括UUID、major、minor,以及距离、openID等信息. + * + * + * + * + * @param ticket the ticket 摇周边业务的ticket,可在摇到的URL中得到,ticket生效时间为30分钟,每一次摇都会重新生成新的ticket + * @return shake user info + * @author fengyapeng + * @since 2016 -10-21 19:34:38 + */ + public ShakeUserInfo getShakeUserInfo(String ticket) throws WeixinException { + String user_get_shake_info_url = getRequestUri("shake_around_user_get_shake_info"); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("ticket", ticket); + WeixinResponse weixinResponse = weixinExecutor + .post(String.format(user_get_shake_info_url, tokenManager.getAccessToken()), jsonObject.toJSONString()); + return weixinResponse.getAsJson().getObject("data", ShakeUserInfo.class); + + } +} diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties index 503db113..faf57280 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties @@ -1,4 +1,4 @@ -# \u5fae\u4fe1\u516c\u4f17\u5e73\u53f0\u6587\u6863\u8bf4\u660e +# \u5FAE\u4FE1\u516C\u4F17\u5E73\u53F0\u6587\u6863\u8BF4\u660E # http://mp.weixin.qq.com/wiki/index.php # ---------------------------------------------------------------------------- @@ -9,186 +9,186 @@ tenpay_base_url=http://mch.tenpay.com tenpay_ssl_base_url=https://mch.tenpay.com tenpay_gw_base_url=https://gw.tenpay.com -# \u7f51\u9875oauth\u6388\u6743URL +# \u7F51\u9875oauth\u6388\u6743URL sns_user_auth_uri=https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect -# \u7b2c\u4e09\u65b9\u7ec4\u4ef6\u4ee3\u516c\u4f17\u53f7\u7f51\u9875oauth\u6388\u6743URL +# \u7B2C\u4E09\u65B9\u7EC4\u4EF6\u4EE3\u516C\u4F17\u53F7\u7F51\u9875oauth\u6388\u6743URL sns_component_user_auth_uri=https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&component_appid=%s#wechat_redirect -# \u7f51\u9875oauth\u6388\u6743\u83b7\u53d6token +# \u7F51\u9875oauth\u6388\u6743\u83B7\u53D6token sns_user_token_uri={api_base_url}/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code -# \u7b2c\u4e09\u65b9\u7ec4\u4ef6\u4ee3\u516c\u4f17\u53f7\u7f51\u9875oauth\u6388\u6743\u83b7\u53d6token +# \u7B2C\u4E09\u65B9\u7EC4\u4EF6\u4EE3\u516C\u4F17\u53F7\u7F51\u9875oauth\u6388\u6743\u83B7\u53D6token sns_component_user_token_uri={api_base_url}/sns/oauth2/component/access_token?appid=%s&code=%s&grant_type=authorization_code&component_appid=%s&component_access_token=%s -# \u7f51\u9875oauth\u6388\u6743\u5237\u65b0token +# \u7F51\u9875oauth\u6388\u6743\u5237\u65B0token sns_token_refresh_uri={api_base_url}/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s -# \u7b2c\u4e09\u65b9\u7ec4\u4ef6\u4ee3\u516c\u4f17\u53f7\u7f51\u9875oauth\u6388\u6743\u5237\u65b0token +# \u7B2C\u4E09\u65B9\u7EC4\u4EF6\u4EE3\u516C\u4F17\u53F7\u7F51\u9875oauth\u6388\u6743\u5237\u65B0token sns_component_token_refresh_uri={api_base_url}/sns/oauth2/component/refresh_token?appid=%s&grant_type=refresh_token&component_appid=%s&component_access_token=%s&refresh_token=%s -# \u7f51\u9875oauthoauth\u6388\u6743\u9a8c\u8bc1token +# \u7F51\u9875oauthoauth\u6388\u6743\u9A8C\u8BC1token sns_auth_token_uri={api_base_url}/sns/auth?access_token=%s&openid=%s -# \u7f51\u9875oauth\u6388\u6743\u83b7\u53d6\u7528\u6237\u4fe1\u606f +# \u7F51\u9875oauth\u6388\u6743\u83B7\u53D6\u7528\u6237\u4FE1\u606F sns_user_info_uri={api_base_url}/sns/userinfo?access_token=%s&openid=%s&lang=%s -# \u5f00\u653e\u5e73\u53f0\u626b\u7801\u767b\u9646\u6388\u6743 +# \u5F00\u653E\u5E73\u53F0\u626B\u7801\u767B\u9646\u6388\u6743 open_user_auth_uri=https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect -# \u76f4\u63a5\u83b7\u53d6\u7528\u6237\u4fe1\u606f +# \u76F4\u63A5\u83B7\u53D6\u7528\u6237\u4FE1\u606F api_user_info_uri={api_cgi_url}/user/info?access_token=%s&openid=%s&lang=%s -# \u6279\u91cf\u83b7\u53d6\u7528\u6237\u4fe1\u606f +# \u6279\u91CF\u83B7\u53D6\u7528\u6237\u4FE1\u606F api_users_info_uri={api_cgi_url}/user/info/batchget?access_token=%s -# \u83b7\u53d6token +# \u83B7\u53D6token api_token_uri={api_cgi_url}/token?grant_type=client_credential&appid=%s&secret=%s -# \u83b7\u53d6\u4e8c\u7ef4\u7801 +# \u83B7\u53D6\u4E8C\u7EF4\u7801 qr_ticket_uri={api_cgi_url}/qrcode/create?access_token=%s qr_image_uri={mp_base_url}/showqrcode?ticket=%s -# \u4e0a\u4f20\u5a92\u4f53\u6587\u4ef6 +# \u4E0A\u4F20\u5A92\u4F53\u6587\u4EF6 media_upload_uri={api_cgi_url}/media/upload?access_token=%s&type=%s -# \u4e0a\u4f20\u56fe\u7247 +# \u4E0A\u4F20\u56FE\u7247 image_upload_uri={api_cgi_url}/media/uploadimg?access_token=%s -# \u4e0b\u8f7d\u5a92\u4f53\u6587\u4ef6 +# \u4E0B\u8F7D\u5A92\u4F53\u6587\u4EF6 meida_download_uri={api_cgi_url}/media/get?access_token=%s&media_id=%s -# \u53d1\u9001\u5ba2\u670d\u6d88\u606f +# \u53D1\u9001\u5BA2\u670D\u6D88\u606F custom_notify_uri={api_cgi_url}/message/custom/send?access_token=%s -# \u521b\u5efa\u5206\u7ec4 +# \u521B\u5EFA\u5206\u7EC4 group_create_uri={api_cgi_url}/groups/create?access_token=%s -# \u67e5\u8be2\u5206\u7ec4 +# \u67E5\u8BE2\u5206\u7EC4 group_get_uri={api_cgi_url}/groups/get?access_token=%s -# \u67e5\u8be2\u7528\u6237\u6240\u5728\u5206\u7ec4 +# \u67E5\u8BE2\u7528\u6237\u6240\u5728\u5206\u7EC4 group_getid_uri={api_cgi_url}/groups/getid?access_token=%s -# \u4fee\u6539\u5206\u7ec4\u540d +# \u4FEE\u6539\u5206\u7EC4\u540D group_modify_uri={api_cgi_url}/groups/update?access_token=%s -# \u79fb\u52a8\u7528\u6237\u5206\u7ec4 +# \u79FB\u52A8\u7528\u6237\u5206\u7EC4 group_move_uri={api_cgi_url}/groups/members/update?access_token=%s -# \u6279\u91cf\u79fb\u52a8\u7528\u6237\u5206\u7ec4 +# \u6279\u91CF\u79FB\u52A8\u7528\u6237\u5206\u7EC4 group_batchmove_uri={api_cgi_url}/groups/members/batchupdate?access_token=%s -# \u5220\u9664\u7528\u6237\u5206\u7ec4 +# \u5220\u9664\u7528\u6237\u5206\u7EC4 group_delete_uri={api_cgi_url}/groups/delete?access_token=%s -# \u83b7\u53d6\u5173\u6ce8\u7740 +# \u83B7\u53D6\u5173\u6CE8\u7740 following_uri={api_cgi_url}/user/get?access_token=%s&next_openid=%s -# \u81ea\u5b9a\u4e49\u83dc\u5355 +# \u81EA\u5B9A\u4E49\u83DC\u5355 menu_create_uri={api_cgi_url}/menu/create?access_token=%s -# \u521b\u5efa\u4e2a\u6027\u5316\u83dc\u5355 +# \u521B\u5EFA\u4E2A\u6027\u5316\u83DC\u5355 menu_custom_create_uri={api_cgi_url}/menu/addconditional?access_token=%s -# \u67e5\u8be2\u83dc\u5355 +# \u67E5\u8BE2\u83DC\u5355 menu_get_uri={api_cgi_url}/menu/get?access_token=%s -# \u67e5\u8be2\u901a\u8fc7\u63a5\u53e3\u6216\u8005\u5728\u516c\u4f17\u5e73\u53f0\u4e0a\u8bbe\u7f6e\u7684\u83dc\u5355\u914d\u7f6e\u4fe1\u606f +# \u67E5\u8BE2\u901A\u8FC7\u63A5\u53E3\u6216\u8005\u5728\u516C\u4F17\u5E73\u53F0\u4E0A\u8BBE\u7F6E\u7684\u83DC\u5355\u914D\u7F6E\u4FE1\u606F menu_get_selfmenu_uri={api_cgi_url}/get_current_selfmenu_info?access_token=%s -# \u5220\u9664\u83dc\u5355 +# \u5220\u9664\u83DC\u5355 menu_delete_uri={api_cgi_url}/menu/delete?access_token=%s -# \u5220\u9664\u4e2a\u6027\u5316\u83dc\u5355 +# \u5220\u9664\u4E2A\u6027\u5316\u83DC\u5355 menu_delete_custom_uri={api_cgi_url}/menu/delconditional?access_token=%s -# \u6d4b\u8bd5\u4e2a\u6027\u5316\u83dc\u5355\u5339\u914d\u7ed3\u679c +# \u6D4B\u8BD5\u4E2A\u6027\u5316\u83DC\u5355\u5339\u914D\u7ED3\u679C menu_trymatch_uri={api_cgi_url}/menu/trymatch?access_token=%s -# \u4e0a\u4f20\u56fe\u6587 +# \u4E0A\u4F20\u56FE\u6587 article_upload_uri={api_cgi_url}/media/uploadnews?access_token=%s -# \u4e0a\u4f20\u89c6\u9891 +# \u4E0A\u4F20\u89C6\u9891 video_upload_uri={api_cgi_url}/media/uploadvideo?access_token=%s -# \u5206\u7ec4\u7fa4\u53d1 +# \u5206\u7EC4\u7FA4\u53D1 mass_group_uri={api_cgi_url}/message/mass/sendall?access_token=%s -# openId\u7fa4\u53d1 +# openId\u7FA4\u53D1 mass_openid_uri={api_cgi_url}/message/mass/send?access_token=%s -# \u5220\u9664\u7fa4\u53d1 +# \u5220\u9664\u7FA4\u53D1 mass_delete_uri={api_cgi_url}/message/mass/delete?access_token=%s -# \u7fa4\u53d1\u9884\u89c8 +# \u7FA4\u53D1\u9884\u89C8 mass_preview_uri={api_cgi_url}/message/mass/preview?access_token=%s -# \u67e5\u8be2\u7fa4\u53d1\u72b6\u6001 +# \u67E5\u8BE2\u7FA4\u53D1\u72B6\u6001 mass_get_uri={api_cgi_url}/message/mass/get?access_token=%s -# \u5ba2\u670d\u804a\u5929\u8bb0\u5f55 +# \u5BA2\u670D\u804A\u5929\u8BB0\u5F55 kf_chatrecord_uri={api_base_url}/customservice/msgrecord/getmsglist?access_token=%s -# \u5ba2\u670d\u57fa\u672c\u4fe1\u606f +# \u5BA2\u670D\u57FA\u672C\u4FE1\u606F kf_list_uri={api_cgi_url}/customservice/getkflist?access_token=%s -# \u5728\u7ebf\u5ba2\u670d\u57fa\u672c\u4fe1\u606f +# \u5728\u7EBF\u5BA2\u670D\u57FA\u672C\u4FE1\u606F kf_onlinelist_uri={api_cgi_url}/customservice/getonlinekflist?access_token=%s -# \u65b0\u589e\u591a\u5ba2\u670d\u8d26\u53f7 +# \u65B0\u589E\u591A\u5BA2\u670D\u8D26\u53F7 kf_create_uri={api_base_url}/customservice/kfaccount/add?access_token=%s -# \u9080\u8bf7\u7ed1\u5b9a\u5ba2\u670d\u5e10\u53f7 +# \u9080\u8BF7\u7ED1\u5B9A\u5BA2\u670D\u5E10\u53F7 kf_invite_uri={api_base_url}customservice/kfaccount/inviteworker?access_token=%s -# \u66f4\u65b0\u591a\u5ba2\u670d\u8d26\u53f7 +# \u66F4\u65B0\u591A\u5BA2\u670D\u8D26\u53F7 kf_update_uri={api_base_url}/customservice/kfaccount/update?access_token=%s -# \u4e0a\u4f20\u5ba2\u670d\u5934\u50cf +# \u4E0A\u4F20\u5BA2\u670D\u5934\u50CF kf_avatar_uri={api_base_url}/customservice/kfacount/uploadheadimg?access_token=%s&kf_account=%s -# \u5220\u9664\u5ba2\u670d\u8d26\u53f7 +# \u5220\u9664\u5BA2\u670D\u8D26\u53F7 kf_delete_uri={api_base_url}/customservice/kfaccount/del?access_token=%s&kf_account=%s -# \u521b\u5efa\u5ba2\u670d\u4f1a\u8bdd +# \u521B\u5EFA\u5BA2\u670D\u4F1A\u8BDD kfsession_create_uri={api_base_url}/customservice/kfsession/create?access_token=%s -# \u5173\u95ed\u5ba2\u670d\u4f1a\u8bdd +# \u5173\u95ED\u5BA2\u670D\u4F1A\u8BDD kfsession_close_uri={api_base_url}/customservice/kfsession/close?access_token=%s -# \u83b7\u53d6\u5ba2\u670d\u4f1a\u8bdd\u72b6\u6001 +# \u83B7\u53D6\u5BA2\u670D\u4F1A\u8BDD\u72B6\u6001 kfsession_get_uri={api_base_url}/customservice/kfsession/getsession?access_token=%s&openid=%s -# \u83b7\u53d6\u5ba2\u670d\u7684\u4f1a\u8bdd\u5217\u8868 +# \u83B7\u53D6\u5BA2\u670D\u7684\u4F1A\u8BDD\u5217\u8868 kfsession_list_uri={api_base_url}/customservice/kfsession/getsessionlist?access_token=%s&kf_account=%s -# \u83b7\u53d6\u672a\u63a5\u5165\u4f1a\u8bdd\u5217\u8868 +# \u83B7\u53D6\u672A\u63A5\u5165\u4F1A\u8BDD\u5217\u8868 kfsession_wait_uri={api_base_url}/customservice/kfsession/getwaitcase?access_token=%s -# \u957f\u94fe\u63a5\u8f6c\u77ed\u94fe\u63a5 +# \u957F\u94FE\u63A5\u8F6C\u77ED\u94FE\u63A5 shorturl_uri={api_cgi_url}/shorturl?access_token=%s -# \u8bbe\u7f6e\u5907\u6ce8\u540d +# \u8BBE\u7F6E\u5907\u6CE8\u540D username_remark_uri={api_cgi_url}/user/info/updateremark?access_token=%s -# \u8bbe\u7f6e\u6a21\u677f\u6d88\u606f\u6240\u5904\u884c\u4e1a +# \u8BBE\u7F6E\u6A21\u677F\u6D88\u606F\u6240\u5904\u884C\u4E1A template_set_industry_uri={api_cgi_url}/template/api_set_industry?access_token=%s -# \u83b7\u53d6\u8bbe\u7f6e\u7684\u884c\u4e1a\u4fe1\u606f +# \u83B7\u53D6\u8BBE\u7F6E\u7684\u884C\u4E1A\u4FE1\u606F template_get_industry_uri={api_cgi_url}/template/get_industry?access_token=%s -# \u83b7\u53d6\u6a21\u677f\u6d88\u606fID +# \u83B7\u53D6\u6A21\u677F\u6D88\u606FID template_getid_uri={api_cgi_url}/template/api_add_template?access_token=%s -# \u83b7\u53d6\u6a21\u677f\u5217\u8868 +# \u83B7\u53D6\u6A21\u677F\u5217\u8868 template_getall_uri={api_cgi_url}/template/get_all_private_template?access_token=%s -# \u5220\u9664\u6a21\u677f +# \u5220\u9664\u6A21\u677F template_del_uri={api_cgi_url}/template/del_private_template?access_token=%s -# \u53d1\u9001\u6a21\u677f\u6d88\u606f +# \u53D1\u9001\u6A21\u677F\u6D88\u606F template_send_uri={api_cgi_url}/message/template/send?access_token=%s -# \u8bed\u4e49\u7406\u89e3 +# \u8BED\u4E49\u7406\u89E3 semantic_uri={api_base_url}/semantic/semproxy/search?access_token=%s -# \u5fae\u4fe1\u670d\u52a1\u5730\u5740 +# \u5FAE\u4FE1\u670D\u52A1\u5730\u5740 getcallbackip_uri={api_cgi_url}/getcallbackip?access_token=%s -# \u63a5\u53e3\u8c03\u7528\u6b21\u6570\u6e05\u96f6 +# \u63A5\u53E3\u8C03\u7528\u6B21\u6570\u6E05\u96F6 clearquota_uri={api_cgi_url}/clear_quota?access_token=%s -# \u6570\u636e\u7edf\u8ba1 +# \u6570\u636E\u7EDF\u8BA1 datacube_uri={api_base_url}/datacube/%s?access_token=%s -##########################\u8001\u7248\u672c\u652f\u4ed8~start -# \u8ba2\u5355\u67e5\u8be2 +##########################\u8001\u7248\u672C\u652F\u4ED8~start +# \u8BA2\u5355\u67E5\u8BE2 orderquery_old_uri={api_base_url}/pay/orderquery?access_token=%s -# \u53d1\u8d27\u901a\u77e5 +# \u53D1\u8D27\u901A\u77E5 delivernotify_old_uri={api_base_url}/pay/delivernotify?access_token=%s -# \u7ef4\u6743\u5904\u7406 +# \u7EF4\u6743\u5904\u7406 payfeedback_old_uri={api_base_url}/payfeedback/update?access_token=%s&openid=%s&feedbackid=%s -# \u5bf9\u8d26\u5355\u4e0b\u8f7d +# \u5BF9\u8D26\u5355\u4E0B\u8F7D downloadbill_old_uri={tenpay_base_url}/cgi-bin/mchdown_real_new.cgi -# \u9000\u6b3e\u67e5\u8be2 +# \u9000\u6B3E\u67E5\u8BE2 refundquery_old_uri={tenpay_gw_base_url}/gateway/normalrefundquery.xml -# \u9000\u6b3e\u7533\u8bf7 +# \u9000\u6B3E\u7533\u8BF7 refundapply_old_uri={tenpay_ssl_base_url}/refundapi/gateway/refund.xml -# native\u652f\u4ed8 +# native\u652F\u4ED8 nativepay_old_uri=weixin://wxpay/bizpayurl?sign=%s&appid=%s&productid=%s×tamp=%s&noncestr=%s -##########################\u8001\u7248\u672c\u652f\u4ed8~end +##########################\u8001\u7248\u672C\u652F\u4ED8~end -# \u4e0a\u4f20\u6c38\u4e45\u56fe\u6587\u7d20\u6750 +# \u4E0A\u4F20\u6C38\u4E45\u56FE\u6587\u7D20\u6750 material_article_upload_uri={api_cgi_url}/material/add_news?access_token=%s -# \u4e0a\u4f20\u6c38\u4e45\u5a92\u4f53\u7d20\u6750 +# \u4E0A\u4F20\u6C38\u4E45\u5A92\u4F53\u7D20\u6750 material_media_upload_uri={api_cgi_url}/material/add_material?access_token=%s -# \u4e0b\u8f7d\u6c38\u4e45\u5a92\u4f53\u7d20\u6750 +# \u4E0B\u8F7D\u6C38\u4E45\u5A92\u4F53\u7D20\u6750 material_media_download_uri={api_cgi_url}/material/get_material?access_token=%s -# \u66f4\u65b0\u6c38\u4e45\u56fe\u6587\u7d20\u6750 +# \u66F4\u65B0\u6C38\u4E45\u56FE\u6587\u7D20\u6750 material_article_update_uri={api_cgi_url}/material/update_news?access_token=%s -# \u5220\u9664\u6c38\u4e45\u5a92\u4f53\u7d20\u6750 +# \u5220\u9664\u6C38\u4E45\u5A92\u4F53\u7D20\u6750 material_media_del_uri={api_cgi_url}/material/del_material?access_token=%s -# \u83b7\u53d6\u5a92\u4f53\u7d20\u6750\u603b\u6570 +# \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 +# \u83B7\u53D6\u5A92\u4F53\u7D20\u6750\u5217\u8868 material_media_list_uri={api_cgi_url}/material/batchget_material?access_token=%s -# \u81ea\u52a8\u56de\u590d\u89c4\u5219 +# \u81EA\u52A8\u56DE\u590D\u89C4\u5219 autoreply_setting_get_uri={api_cgi_url}/get_current_autoreply_info?access_token=%s -# \u521b\u5efa\u6807\u7b7e +# \u521B\u5EFA\u6807\u7B7E tag_create_uri={api_cgi_url}/tags/create?access_token=%s -# \u83b7\u53d6\u6807\u7b7e +# \u83B7\u53D6\u6807\u7B7E tag_get_uri={api_cgi_url}/tags/get?access_token=%s -# \u66f4\u65b0\u6807\u7b7e +# \u66F4\u65B0\u6807\u7B7E tag_update_uri={api_cgi_url}/tags/update?access_token=%s -# \u5220\u9664\u6807\u7b7e +# \u5220\u9664\u6807\u7B7E tag_delete_uri={api_cgi_url}/tags/delete?access_token=%s -# \u4e3a\u7528\u6237\u6253\u6807\u7b7e +# \u4E3A\u7528\u6237\u6253\u6807\u7B7E tag_tagging_uri={api_cgi_url}/tags/members/batchtagging?access_token=%s -# \u4e3a\u7528\u6237\u53d6\u6d88\u6807\u7b7e +# \u4E3A\u7528\u6237\u53D6\u6D88\u6807\u7B7E tag_untagging_uri={api_cgi_url}/tags/members/batchuntagging?access_token=%s -# \u83b7\u53d6\u7528\u6237\u8eab\u4e0a\u7684\u6807\u7b7e\u5217\u8868 +# \u83B7\u53D6\u7528\u6237\u8EAB\u4E0A\u7684\u6807\u7B7E\u5217\u8868 tag_userids_uri={api_cgi_url}/tags/getidlist?access_token=%s -# \u83b7\u53d6\u6807\u7b7e\u4e0b\u7c89\u4e1d\u5217\u8868 +# \u83B7\u53D6\u6807\u7B7E\u4E0B\u7C89\u4E1D\u5217\u8868 tag_user_uri={api_cgi_url}/user/tag/get?access_token=%s # \u83b7\u53d6\u9ed1\u540d\u5355\u5217\u8868 getblacklist_uri={api_cgi_url}/tags/members/getblacklist?access_token=%s @@ -197,20 +197,31 @@ batchblacklist_uri={api_cgi_url}/tags/members/batchblacklist?access_token=%s # \u53d6\u6d88\u62c9\u9ed1\u7528\u6237 batchunblacklist_uri={api_cgi_url}/tags/members/batchunblacklist?access_token=%s -# \u521b\u5efa\u5361\u5238 +# \u521B\u5EFA\u5361\u5238 card_create_uri={api_base_url}/card/create?access_token=%s -# \u8bbe\u7f6e\u4e70\u5355\u63a5\u53e3 +# \u8BBE\u7F6E\u4E70\u5355\u63A5\u53E3 card_paycell_uri={api_base_url}/card/paycell/set?access_token=%s -# \u8bbe\u7f6e\u81ea\u52a9\u6838\u9500\u63a5\u53e3 +# \u8BBE\u7F6E\u81EA\u52A9\u6838\u9500\u63A5\u53E3 card_selfconsumecell_uri={api_base_url}/card/selfconsumecell/set?access_token=%s -# \u521b\u5efa\u5361\u5238\u4e8c\u7ef4\u7801\u63a5\u53e3 +# \u521B\u5EFA\u5361\u5238\u4E8C\u7EF4\u7801\u63A5\u53E3 card_qr_ticket_uri={api_base_url}/card/qrcode/create?access_token=%s -# \u4f7f\u7528\u6388\u6743\u7801\u6362\u53d6\u516c\u4f17\u53f7\u7684\u63a5\u53e3\u8c03\u7528\u51ed\u636e\u548c\u6388\u6743\u4fe1\u606f +# \u4F7F\u7528\u6388\u6743\u7801\u6362\u53D6\u516C\u4F17\u53F7\u7684\u63A5\u53E3\u8C03\u7528\u51ED\u636E\u548C\u6388\u6743\u4FE1\u606F component_exchange_authorizer_uri={api_cgi_url}/component/api_query_auth?component_access_token=%s -# \u83b7\u53d6\u6388\u6743\u65b9\u7684\u516c\u4f17\u53f7\u5e10\u53f7\u57fa\u672c\u4fe1\u606f +# \u83B7\u53D6\u6388\u6743\u65B9\u7684\u516C\u4F17\u53F7\u5E10\u53F7\u57FA\u672C\u4FE1\u606F component_get_authorizer_uri={api_cgi_url}/component/api_get_authorizer_info?component_access_token=%s -# \u83b7\u53d6\u6388\u6743\u65b9\u7684\u9009\u9879\u8bbe\u7f6e\u4fe1\u606f +# \u83B7\u53D6\u6388\u6743\u65B9\u7684\u9009\u9879\u8BBE\u7F6E\u4FE1\u606F component_get_authorizer_option_uri={api_cgi_url}/component/api_get_authorizer_option?component_access_token=%s -# \u8bbe\u7f6e\u6388\u6743\u65b9\u7684\u9009\u9879\u4fe1\u606f -component_set_authorizer_option_uri={api_cgi_url}component/api_set_authorizer_option?component_access_token=%s \ No newline at end of file +# \u8BBE\u7F6E\u6388\u6743\u65B9\u7684\u9009\u9879\u4FE1\u606F +component_set_authorizer_option_uri={api_cgi_url}component/api_set_authorizer_option?component_access_token=%s + +# \u6447\u4E00\u6447\u5468\u8FB9-\u7533\u8BF7\u8BBE\u5907ID +shake_around_device_apply_uri={api_base_url}/shakearound/device/applyid?access_token=%s +# \u6447\u4E00\u6447\u5468\u8FB9-\u8BBE\u5907ID\u7533\u8BF7\u72B6\u6001\u67E5\u8BE2 +shake_around_device_apply_status_uri={api_base_url}/shakearound/device/applystatus?access_token=%s +#\u6447\u4E00\u6447\u5468\u8FB9-\u8BBE\u5907\u7F16\u8F91\u5907\u6CE8\u4FE1\u606F +shake_around_device_update_uri={api_base_url}/shakearound/device/update?access_token=%s +#\u6447\u4E00\u6447\u5468\u8FB9-\u67E5\u8BE2\u8BBE\u5907\u5217\u8868 +shake_around_device_search_uri={api_base_url}/shakearound/device/search?access_token=%s +#\u6447\u4E00\u6447\u5468\u8FB9-\u83B7\u53D6\u8BBE\u5907\u548C\u7528\u6237\u4FE1\u606F +shake_around_user_get_shake_info={api_base_url}/shakearound/user/getshakeinfo?access_token=%s \ No newline at end of file diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/shakearound/Device.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/shakearound/Device.java new file mode 100644 index 00000000..bdfadd6b --- /dev/null +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/shakearound/Device.java @@ -0,0 +1,158 @@ +package com.foxinmy.weixin4j.mp.model.shakearound; + +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 摇一摇设备信息。device_id 和 uuid major minor 可以2者选一 + * @auther: Feng Yapeng + * @since: 2016/10/13 9:59 + */ +public class Device { + + /** + * 设备编号 + */ + @JSONField(name = "device_id") + private Integer deviceId; + + + private String uuid; + + private Integer major; + + private Integer minor; + + /** + * 激活状态,0:未激活,1:已激活 + */ + private int status; + + /** + * 设备最近一次被摇到的日期(最早只能获取前一天的数据);新申请的设备该字段值为0 + */ + @JSONField(name = "last_active_time") + private String lastActiveTime; + + /** + * 若配置了设备与其他公众账号门店关联关系,则返回配置门店归属的公众账号appid。 + * 查看配置设备与其他公众账号门店关联关系接口 + */ + @JSONField(name = "poi_appid") + private String poiAppId; + + /** + * 设备关联的门店ID,关联门店后,在门店1KM的范围内有优先摇出信息的机会。 + * 门店相关信息具体可查看门店相关的接口文档 + */ + @JSONField(name = "poi_id") + private String poiId; + + /** + * 设备的备注信息 + */ + private String comment; + + + public Device() { + } + + /** + * + * @param deviceId + */ + public Device(Integer deviceId) { + this.deviceId = deviceId; + } + + public Device(String uuid, Integer major, Integer minor) { + this.uuid = uuid; + this.major = major; + this.minor = minor; + } + + public Integer getDeviceId() { + return deviceId; + } + + public void setDeviceId(int deviceId) { + this.deviceId = deviceId; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public Integer getMajor() { + return major; + } + + public void setMajor(int major) { + this.major = major; + } + + public Integer getMinor() { + return minor; + } + + public void setMinor(int minor) { + this.minor = minor; + } + + public void setDeviceId(Integer deviceId) { + this.deviceId = deviceId; + } + + public void setMajor(Integer major) { + this.major = major; + } + + public void setMinor(Integer minor) { + this.minor = minor; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getLastActiveTime() { + return lastActiveTime; + } + + public void setLastActiveTime(String lastActiveTime) { + this.lastActiveTime = lastActiveTime; + } + + public String getPoiAppId() { + return poiAppId; + } + + public void setPoiAppId(String poiAppId) { + this.poiAppId = poiAppId; + } + + public String getPoiId() { + return poiId; + } + + public void setPoiId(String poiId) { + this.poiId = poiId; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + +} diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/shakearound/DeviceAuditState.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/shakearound/DeviceAuditState.java new file mode 100644 index 00000000..7594a883 --- /dev/null +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/shakearound/DeviceAuditState.java @@ -0,0 +1,84 @@ +package com.foxinmy.weixin4j.mp.model.shakearound; + +import com.alibaba.fastjson.annotation.JSONField; + +import java.util.Date; + +/** + * 摇一摇周边设备审核信息 + * + * @auther: Feng Yapeng + * @since: 2016/10/12 21:47 + */ +public class DeviceAuditState { + + /** + * 申请设备ID时所返回的批次ID + */ + @JSONField(name = "apply_id") + private Integer applyId; + /** + * 审核状态。0:审核未通过、1:审核中、2:审核已通过; + * 若单次申请的设备ID数量小于等于500个,系统会进行快速审核; + * 若单次申请的设备ID数量大于500个,会在三个工作日内完成审核; + */ + @JSONField(name = "audit_status") + private String auditStatus; + + /** + * 审核备注,对审核状态的文字说明 + */ + @JSONField(name = "audit_comment") + private String auditComment; + /** + * 提交申请的时间戳 + */ + @JSONField(name = "apply_time") + private long applyTime; + + /** + * 确定审核结果的时间戳,若状态为审核中,则该时间值为0 + */ + @JSONField(name = "audit_time") + private long auditTime; + + public Integer getApplyId() { + return applyId; + } + + public void setApplyId(Integer applyId) { + this.applyId = applyId; + } + + public String getAuditStatus() { + return auditStatus; + } + + public void setAuditStatus(String auditStatus) { + this.auditStatus = auditStatus; + } + + public String getAuditComment() { + return auditComment; + } + + public void setAuditComment(String auditComment) { + this.auditComment = auditComment; + } + + public long getApplyTime() { + return applyTime; + } + + public void setApplyTime(long applyTime) { + this.applyTime = applyTime; + } + + public long getAuditTime() { + return auditTime; + } + + public void setAuditTime(long auditTime) { + this.auditTime = auditTime; + } +} diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/shakearound/ShakeUserInfo.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/shakearound/ShakeUserInfo.java new file mode 100644 index 00000000..37260164 --- /dev/null +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/shakearound/ShakeUserInfo.java @@ -0,0 +1,58 @@ +package com.foxinmy.weixin4j.mp.model.shakearound; + +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 获取设备信息,包括UUID、major、minor,以及距离、openID等信息。 + * + * @author fengyapeng + * @auther: Feng Yapeng + * @since: 2016 /10/21 19:21 + * @since 2016 -10-21 19:21:59 + */ +public class ShakeUserInfo { + + + @JSONField(name = "page_id") + private Long pageId; + @JSONField(name = "beacon_info") + private Device device; + + @JSONField(name = "poi_id") + private Long poiId; + + @JSONField(name = "openid") + private String openId; + + public Long getPageId() { + return pageId; + } + + public void setPageId(Long pageId) { + this.pageId = pageId; + } + + public Device getDevice() { + return device; + } + + public void setDevice(Device device) { + this.device = device; + } + + public Long getPoiId() { + return poiId; + } + + public void setPoiId(Long poiId) { + this.poiId = poiId; + } + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } +} diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/HelpTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/HelpTest.java new file mode 100644 index 00000000..c2e0e06b --- /dev/null +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/HelpTest.java @@ -0,0 +1,35 @@ +package com.foxinmy.weixin4j.mp.test; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.mp.api.HelperApi; + +public class HelpTest extends TokenTest { + private HelperApi helperApi; + + @Before + public void init() { + helperApi = new HelperApi(tokenManager); + } + + @Test + public void getWechatServerIp() throws WeixinException { + List ipList = helperApi.getWechatServerIp(); + Assert.assertFalse(ipList.isEmpty()); + } + + @Test + public void getMenuSetting() throws WeixinException { + System.err.println(helperApi.getMenuSetting()); + } + + @Test + public void getAutoReplySetting() throws WeixinException { + System.err.println(helperApi.getAutoReplySetting()); + } +} From bdf63e3fc412736d1bd143f2a9aa11b5fc3fdde0 Mon Sep 17 00:00:00 2001 From: fengyapeng Date: Thu, 22 Dec 2016 09:44:10 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BC=9A=E5=91=98?= =?UTF-8?q?=E5=8D=A1=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin4j/model/card/CardCoupons.java | 3 + .../weixin4j/model/card/MemberInitInfo.java | 171 ++++++++++++++ .../weixin4j/model/card/MemberUpdateInfo.java | 210 ++++++++++++++++++ .../weixin4j/model/card/MemberUserForm.java | 159 +++++++++++++ .../weixin4j/model/card/MemberUserInfo.java | 165 ++++++++++++++ .../type/card/ActivateCommonField.java | 66 ++++++ .../type/card/ActivateFormFieldType.java | 16 ++ .../weixin4j/type/card/UserCardStatus.java | 19 ++ .../com/foxinmy/weixin4j/mp/api/CardApi.java | 77 ++++++- .../weixin4j/mp/api/MemberCardApi.java | 95 ++++++++ .../foxinmy/weixin4j/mp/api/weixin.properties | 20 +- .../weixin4j/mp/test/MemberCardTest.java | 16 ++ 12 files changed, 1013 insertions(+), 4 deletions(-) create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberInitInfo.java create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUpdateInfo.java create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUserForm.java create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUserInfo.java create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/ActivateCommonField.java create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/ActivateFormFieldType.java create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/UserCardStatus.java create mode 100644 weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MemberCardApi.java create mode 100644 weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupons.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupons.java index 88c75578..41508381 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupons.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupons.java @@ -35,6 +35,9 @@ public final class CardCoupons { return new CouponAdvanceInfo.Builder(); } + public static MemberCard.Builder customMemberCard(){ + return new MemberCard.Builder(); + } /** * 创建代金券 * diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberInitInfo.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberInitInfo.java new file mode 100644 index 00000000..66ebe3d5 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberInitInfo.java @@ -0,0 +1,171 @@ +package com.foxinmy.weixin4j.model.card; + +import com.alibaba.fastjson.annotation.JSONField; + +import java.util.Date; + +/** + * 会员初始化的信息 + * + * @auther: Feng Yapeng + * @since: 2016/12/20 15:00 + */ +public class MemberInitInfo { + + /** + * 会员卡编号,由开发者填入,作为序列号显示在用户的卡包里。可与Code码保持等值。 + */ + @JSONField(name = "membership_number") + private String membershipNumber; + /** + * 领取会员卡用户获得的code + */ + private String code; + /** + * 卡券ID【自定义code卡券必填】 + */ + @JSONField(name = "card_id") + private String cardId; + /** + * 商家自定义会员卡背景图,须 先调用上传图片接口将背景图上传至CDN,否则报错, + * 卡面设计请遵循微信会员卡自定义背景设计规范 + */ + @JSONField(name = "background_pic_url") + private String backgroundPicUrl; + + /** + * 激活后的有效起始时间。若不填写默认以创建时的 date_info 为准。Unix时间戳格式 + */ + @JSONField(name = "activate_begin_time") + private long activateBeginTime; + /** + * 激活后的有效截至时间。 + */ + @JSONField(name = "activate_end_time") + private long activateEndTime; + /** + * 初始积分,不填为0。 + */ + @JSONField(name = "init_bonus") + private Integer initBonus; + /** + * 积分同步说明。 + */ + @JSONField(name = "init_bonus_record") + private String initBonusRecord; + + + /** + * 初始余额,不填为0。 + */ + @JSONField(name = "init_balance") + private Integer initBalance; + /** + * 创建时字段custom_field1定义类型的初始值,限制为4个汉字,12字节。 + */ + private String init_custom_field_value1; + /** + * 创建时字段custom_field2定义类型的初始值,限制为4个汉字,12字节。 + */ + private String init_custom_field_value2; + /** + * 创建时字段custom_field3定义类型的初始值,限制为4个汉字,12字节。 + */ + private String init_custom_field_value3; + + public String getMembershipNumber() { + return membershipNumber; + } + + public void setMembershipNumber(String membershipNumber) { + this.membershipNumber = membershipNumber; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getCardId() { + return cardId; + } + + public void setCardId(String cardId) { + this.cardId = cardId; + } + + public String getBackgroundPicUrl() { + return backgroundPicUrl; + } + + public void setBackgroundPicUrl(String backgroundPicUrl) { + this.backgroundPicUrl = backgroundPicUrl; + } + + public long getActivateBeginTime() { + return activateBeginTime; + } + + public void setActivateBeginTime(Date activateBeginTime) { + this.activateBeginTime = activateBeginTime.getTime() / 1000; + } + + public long getActivateEndTime() { + return activateEndTime; + } + + public void setActivateEndTime(Date activateEndTime) { + this.activateEndTime = activateEndTime.getTime() / 1000; + } + + public Integer getInitBonus() { + return initBonus; + } + + public void setInitBonus(Integer initBonus) { + this.initBonus = initBonus; + } + + public String getInitBonusRecord() { + return initBonusRecord; + } + + public void setInitBonusRecord(String initBonusRecord) { + this.initBonusRecord = initBonusRecord; + } + + public Integer getInitBalance() { + return initBalance; + } + + public void setInitBalance(Integer initBalance) { + this.initBalance = initBalance; + } + + public String getInit_custom_field_value1() { + return init_custom_field_value1; + } + + public void setInit_custom_field_value1(String init_custom_field_value1) { + this.init_custom_field_value1 = init_custom_field_value1; + } + + public String getInit_custom_field_value2() { + return init_custom_field_value2; + } + + public void setInit_custom_field_value2(String init_custom_field_value2) { + this.init_custom_field_value2 = init_custom_field_value2; + } + + public String getInit_custom_field_value3() { + return init_custom_field_value3; + } + + public void setInit_custom_field_value3(String init_custom_field_value3) { + this.init_custom_field_value3 = init_custom_field_value3; + } +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUpdateInfo.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUpdateInfo.java new file mode 100644 index 00000000..9d5a58ca --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUpdateInfo.java @@ -0,0 +1,210 @@ +package com.foxinmy.weixin4j.model.card; + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 会员更新的信息 + * + * @auther: Feng Yapeng + * @since: 2016/12/20 15:01 + */ +public class MemberUpdateInfo { + + /** + * 卡券Code码。 + */ + private String code; + /** + * 卡券ID。 + */ + @JSONField(name = "card_id") + private String cardId; + /** + * 支持商家激活时针对单个会员卡分配自定义的会员卡背景。 + */ + @JSONField(name = "background_pic_url") + private String backgroundPicUrl; + /** + * 需要设置的积分全量值,传入的数值会直接显示 + */ + private Integer bonus; + /** + * 本次积分变动值,传负数代表减少 + */ + @JSONField(name = "add_bonus") + private Integer addBonus; + /** + * 商家自定义积分消耗记录,不超过14个汉字 + */ + @JSONField(name = "record_bonus") + private String recordBonus; + /* + * 需要设置的余额全量值,传入的数值会直接显示在卡面 + */ + private Integer balance; + + /** + * 本次余额变动值,传负数代表减少 + */ + @JSONField(name = "add_balance") + private Integer addBalance; + /** + * 商家自定义金额消耗记录,不超过14个汉字。 + */ + @JSONField(name = "record_balance") + private String recordBalance; + /** + * 创建时字段custom_field1定义类型的最新数值,限制为4个汉字,12字节。 + */ + @JSONField(name = "custom_field_value1") + private String customFieldValue1; + /** + * 同上 + */ + @JSONField(name = "custom_field_value2") + private String customFieldValue2; + /** + * 同上 + */ + @JSONField(name = "custom_field_value3") + private String customFieldValue3; + + /** + * + */ + @JSONField(name = "notifyOptional") + private JSONObject notifyOptional; + + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getCardId() { + return cardId; + } + + public void setCardId(String cardId) { + this.cardId = cardId; + } + + public String getBackgroundPicUrl() { + return backgroundPicUrl; + } + + public void setBackgroundPicUrl(String backgroundPicUrl) { + this.backgroundPicUrl = backgroundPicUrl; + } + + public Integer getBonus() { + return bonus; + } + + public void setBonus(Integer bonus) { + this.bonus = bonus; + } + + public Integer getAddBonus() { + return addBonus; + } + + public void setAddBonus(Integer addBonus) { + this.addBonus = addBonus; + } + + public String getRecordBonus() { + return recordBonus; + } + + public void setRecordBonus(String recordBonus) { + this.recordBonus = recordBonus; + } + + public Integer getBalance() { + return balance; + } + + public void setBalance(Integer balance) { + this.balance = balance; + } + + public Integer getAddBalance() { + return addBalance; + } + + public void setAddBalance(Integer addBalance) { + this.addBalance = addBalance; + } + + public String getRecordBalance() { + return recordBalance; + } + + public void setRecordBalance(String recordBalance) { + this.recordBalance = recordBalance; + } + + public String getCustomFieldValue1() { + return customFieldValue1; + } + + public void setCustomFieldValue1(String customFieldValue1) { + this.customFieldValue1 = customFieldValue1; + } + + public void setCustomFieldValue1(String customFieldValue1, boolean notify) { + this.customFieldValue1 = customFieldValue1; + if (notifyOptional == null) { + notifyOptional = new JSONObject(); + } + notifyOptional.put("is_notify_custom_field1", notify); + } + + + public String getCustomFieldValue2() { + return customFieldValue2; + } + + public void setCustomFieldValue2(String customFieldValue2) { + this.customFieldValue2 = customFieldValue2; + + } + + public void setCustomFieldValue2(String customFieldValue2, boolean notify) { + this.customFieldValue2 = customFieldValue2; + if (notifyOptional == null) { + notifyOptional = new JSONObject(); + } + notifyOptional.put("is_notify_custom_field2", notify); + + } + + public String getCustomFieldValue3() { + return customFieldValue3; + } + + public void setCustomFieldValue3(String customFieldValue3) { + this.customFieldValue3 = customFieldValue3; + } + + public void setCustomFieldValue3(String customFieldValue3, boolean notify) { + this.customFieldValue3 = customFieldValue3; + if (notifyOptional == null) { + notifyOptional = new JSONObject(); + } + notifyOptional.put("is_notify_custom_field3", notify); + } + + public void setNOtify(boolean notifyBonus, boolean notifyBalance) { + if (notifyOptional == null) { + notifyOptional = new JSONObject(); + } + notifyOptional.put("is_notify_bonus", notifyBonus); + notifyOptional.put("is_notify_balance", notifyBalance); + } +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUserForm.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUserForm.java new file mode 100644 index 00000000..5dc69e59 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUserForm.java @@ -0,0 +1,159 @@ +package com.foxinmy.weixin4j.model.card; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.type.card.ActivateCommonField; +import com.foxinmy.weixin4j.type.card.ActivateFormFieldType; + +import java.util.HashSet; + +/** + * 普通一键激活 中设置会员卡 + * + * @auther: Feng Yapeng + * @since: 2016/12/20 16:25 + */ +public class MemberUserForm { + + /** + * 卡券ID。 + */ + @JSONField(name = "card_id") + private String cardId; + + /** + * 服务声明,用于放置商户会员卡守则 + */ + @JSONField(name = "service_statement") + private JSONObject serviceStatement; + /** + * 绑定老会员链接 + */ + @JSONField(name = "bind_old_card") + private JSONObject bindOldCard; + + /** + *设置必填的from + */ + @JSONField(name = "required_form") + private FormBudiler requiredForm; + + /** + * 设置选填的form + */ + @JSONField(name = "optional_form") + private FormBudiler optionalForm; + + + public String getCardId() { + return cardId; + } + + public void setCardId(String cardId) { + this.cardId = cardId; + } + + public JSONObject getServiceStatement() { + return serviceStatement; + } + + public void setServiceStatement(String name,String url) { + JSONObject serviceStatement = new JSONObject(); + serviceStatement.put("name",name); + serviceStatement.put("url",url); + this.serviceStatement = serviceStatement; + } + + public JSONObject getBindOldCard() { + return bindOldCard; + } + + public void setBindOldCard(String name,String url) { + JSONObject bindOldCard = new JSONObject(); + bindOldCard.put("name",name); + bindOldCard.put("url",url); + this.bindOldCard = bindOldCard; + } + + public void setRequiredForm(FormBudiler formBudiler) { + this.requiredForm = formBudiler; + } + + public void setOptionalForm(FormBudiler formBudiler) { + this.optionalForm = formBudiler; + } + + public final static class FormBudiler { + + /** + * 当前结构(required_form或者optional_form )内 + * 的字段是否允许用户激活后再次修改,商户设置为true + * 时,需要接收相应事件通知处理修改事件 + */ + private boolean canModify; + /** + * 自定义富文本类型,包含以下三个字段 + */ + @JSONField(name = "rich_field_list") + private JSONArray richFieldList; + + /** + * 微信格式化的选项类型 + */ + @JSONField(name = "common_field_id_list") + private HashSet commonFieldIdList; + + /** + * 自定义选项名称。 + */ + @JSONField(name = "custom_field_list") + private HashSet customFieldList; + + /** + * 自定义富文本类型 + */ + private FormBudiler addRichField(ActivateFormFieldType fieldType, String name, String... values) { + if (richFieldList == null) { + richFieldList = new JSONArray(); + } + JSONObject obj = new JSONObject(); + obj.put("type", fieldType); + obj.put("name", name); + obj.put("values", values); + richFieldList.add(obj); + return this; + } + + /** + * 自定义公共字段 + */ + public FormBudiler addCommonField(ActivateCommonField... fields) { + if (commonFieldIdList == null) { + commonFieldIdList = new HashSet(); + } + for (ActivateCommonField field : fields) { + commonFieldIdList.add(field); + } + return this; + } + + /** + * 增加自定义的内容 + * @param names + */ + public FormBudiler addCustomField(String... names) { + if (customFieldList == null) { + customFieldList = new HashSet(); + } + for (String name : names) { + customFieldList.add(name); + } + return this; + } + + + + } + +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUserInfo.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUserInfo.java new file mode 100644 index 00000000..fc4b4070 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUserInfo.java @@ -0,0 +1,165 @@ +package com.foxinmy.weixin4j.model.card; + +import com.alibaba.fastjson.annotation.JSONField; +import com.alibaba.fastjson.annotation.JSONType; +import com.foxinmy.weixin4j.type.Gender; +import com.foxinmy.weixin4j.type.card.UserCardStatus; +import com.foxinmy.weixin4j.util.NameValue; +import com.foxinmy.weixin4j.xml.ListsuffixResult; + +import java.util.ArrayList; +import java.util.Map; + +/** + * 会员卡的基本信息 + * + * @auther: Feng Yapeng + * @since: 2016/12/21 11:33 + */ +public class MemberUserInfo { + + /** + * openId + */ + @JSONField(name = "openid") + private String openId; + /** + * 昵称 + */ + @JSONField(name = "nickname") + private String nickName; + + /** + * 会员卡编号 + */ + @JSONField(name = "mmebership_number") + private String membershipNumber; + /** + * 积分 + */ + private Integer bonus; + /** + * 余额 + */ + private Integer balance; + /** + * 性别 + */ + private String sex; + /** + * 用户会员卡状态 + */ + @JSONField(name = "user_card_status") + private UserCardStatus userCardStatus; + + /** + * 是否已经被激活,true表示已经被激活,false表示未被激活 + */ + @JSONField(name = "has_active") + private boolean hasActive; + + /** + * 用户信息 + */ + @JSONField(name = "user_info") + private UserInfo userInfo; + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getMembershipNumber() { + return membershipNumber; + } + + public void setMembershipNumber(String membershipNumber) { + this.membershipNumber = membershipNumber; + } + + public Integer getBonus() { + return bonus; + } + + public void setBonus(Integer bonus) { + this.bonus = bonus; + } + + public Integer getBalance() { + return balance; + } + + public void setBalance(Integer balance) { + this.balance = balance; + } + + public String getSex() { + return sex; + } + + public void setSex(String sex) { + this.sex = sex; + } + + public UserCardStatus getUserCardStatus() { + return userCardStatus; + } + + public void setUserCardStatus(UserCardStatus userCardStatus) { + this.userCardStatus = userCardStatus; + } + + public boolean isHasActive() { + return hasActive; + } + + public void setHasActive(boolean hasActive) { + this.hasActive = hasActive; + } + + public UserInfo getUserInfo() { + return userInfo; + } + + public void setUserInfo(UserInfo userInfo) { + this.userInfo = userInfo; + } + + public static final class UserInfo { + + @JSONField(name = "common_field_list") + private ArrayList commonFieldValues; + + @JSONField(name = "custom_field_list") + private ArrayList customFieldValues; + + public ArrayList getCommonFieldValues() { + return commonFieldValues; + } + + public void setCommonFieldValues(ArrayList commonFieldValues) { + this.commonFieldValues = commonFieldValues; + } + + public ArrayList getCustomFieldValues() { + return customFieldValues; + } + + public void setCustomFieldValues(ArrayList customFieldValues) { + this.customFieldValues = customFieldValues; + } + } + + +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/ActivateCommonField.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/ActivateCommonField.java new file mode 100644 index 00000000..a9f1611f --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/ActivateCommonField.java @@ -0,0 +1,66 @@ +package com.foxinmy.weixin4j.type.card; + +/** + * 会员卡激活设置公共字段类型 + * + * @auther: Feng Yapeng + * @since: 2016/12/20 14:49 + */ +public enum ActivateCommonField { + + /** + * 手机号 + */ + USER_FORM_INFO_FLAG_MOBILE, + + /** + * 性别 + */ + USER_FORM_INFO_FLAG_SEX, + + /** + * 姓名 + */ + USER_FORM_INFO_FLAG_NAME, + + /** + * 生日 + */ + USER_FORM_INFO_FLAG_BIRTHDAY, + + /** + * 身份证 + */ + USER_FORM_INFO_FLAG_IDCARD, + + /** + * 邮箱 + */ + USER_FORM_INFO_FLAG_EMAIL, + + /** + * 详细地址 + */ + USER_FORM_INFO_FLAG_LOCATION, + + /** + * 教育背景 + */ + USER_FORM_INFO_FLAG_EDUCATION_BACKGRO, + + /** + * 行业 + */ + USER_FORM_INFO_FLAG_INDUSTRY, + + /** + * 收入 + */ + USER_FORM_INFO_FLAG_INCOME, + + /** + * 兴趣爱好 + */ + USER_FORM_INFO_FLAG_HABIT; + +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/ActivateFormFieldType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/ActivateFormFieldType.java new file mode 100644 index 00000000..e70c35e9 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/ActivateFormFieldType.java @@ -0,0 +1,16 @@ +package com.foxinmy.weixin4j.type.card; + +/** + * 激活form表单字段类型 + * + * @auther: Feng Yapeng + * @since: 2016/12/20 15:34 + */ +public enum ActivateFormFieldType { + + FORM_FIELD_RADIO,/*自定义单选 */ + + FORM_FIELD_SELECT,/*自定义选择项 */ + + FORM_FIELD_CHECK_BOX,/*自定义多选*/; +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/UserCardStatus.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/UserCardStatus.java new file mode 100644 index 00000000..2fcdef87 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/card/UserCardStatus.java @@ -0,0 +1,19 @@ +package com.foxinmy.weixin4j.type.card; + +/** + * 用户的会员卡状态 + * + * @auther: Feng Yapeng + * @since: 2016/12/21 11:42 + */ +public enum UserCardStatus { + + NORMAL,//正常 + EXPIRE,//已过期 + GIFTING,// 转赠中 + GIFT_SUCC,// 转赠成功 + GIFT_TIMEOUT,// 转赠超时 + DELETE,//已删除 + UNAVAILABLE,//已失效 + ; +} diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CardApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CardApi.java index a3fc98b4..9d4f17fd 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CardApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CardApi.java @@ -1,6 +1,7 @@ package com.foxinmy.weixin4j.mp.api; import java.io.IOException; +import java.util.List; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; @@ -15,6 +16,7 @@ import com.foxinmy.weixin4j.model.card.CardQR; import com.foxinmy.weixin4j.model.qr.QRParameter; import com.foxinmy.weixin4j.model.qr.QRResult; import com.foxinmy.weixin4j.token.TokenManager; +import com.foxinmy.weixin4j.type.card.CardType; import com.foxinmy.weixin4j.util.IOUtil; /** @@ -28,7 +30,7 @@ import com.foxinmy.weixin4j.util.IOUtil; * href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025056&token=&lang=zh_CN">卡券说明 */ public class CardApi extends MpApi { - private final TokenManager tokenManager; + protected final TokenManager tokenManager; public CardApi(TokenManager tokenManager) { this.tokenManager = tokenManager; @@ -155,4 +157,77 @@ public class CardApi extends MpApi { } return result; } + + /** + * 由于卡券有审核要求,为方便公众号调试,可以设置一些测试帐号,这些帐号可领取未通过审核的卡券,体验整个流程。 + * 1.同时支持“openid”、“username”两种字段设置白名单,总数上限为10个。 + * 2.设置测试白名单接口为全量设置,即测试名单发生变化时需调用该接口重新传入所有测试人员的ID. + * 3.白名单用户领取该卡券时将无视卡券失效状态,请开发者注意。 + * @param openIds the open ids + * @param userNames the user names + * @author fengyapeng + * @since 2016 -12-20 11:22:57 + * @see 设置测试白名单 + */ + public void setTestWhiteList(List openIds, List userNames) throws WeixinException { + JSONObject requestObj = new JSONObject(); + if (openIds != null && openIds.size() > 0) { + requestObj.put("openid", openIds); + } + if (userNames != null && userNames.size() > 0) { + requestObj.put("username", userNames); + } + String card_set_test_whitelist_uri = getRequestUri("card_set_test_whitelist_uri"); + Token token = tokenManager.getCache(); + WeixinResponse response = weixinExecutor.post( + String.format(card_set_test_whitelist_uri, token.getAccessToken()), + requestObj.toJSONString()); + } + + /** + * 查看获取卡券的审核状态 + * @see 查看卡券详情 + * + * @author fengyapeng + * @since 2016 -12-20 11:48:23 + */ + public void getCardStatus(String cardId) throws WeixinException { + JSONObject requestObj = new JSONObject(); + requestObj.put("card_id",cardId); + String card_get_uri = getRequestUri("card_get_uri"); + Token token = tokenManager.getCache(); + WeixinResponse response = weixinExecutor.post(String.format(card_get_uri, token.getAccessToken()),requestObj.toJSONString()); + JSONObject responseAsJson = response.getAsJson(); + JSONObject card = responseAsJson.getJSONObject("card"); + String cardType = card.getString("card_type"); + JSONObject baseInfo = card.getJSONObject(cardType.toLowerCase()).getJSONObject("base_info"); + baseInfo.get("status"); + } + + /** + * 支持更新所有卡券类型的部分通用字段及特殊卡券(会员卡、飞机票、电影票、会议门票)中特定字段的信息。 + * + * @param cardId the card id + * @param card the card + * @return 是否提交审核,false为修改后不会重新提审,true为修改字段后重新提审,该卡券的状态变为审核中 + * @throws WeixinException the weixin exception + * @author fengyapeng + * @see + * @since 2016 -12-21 15:29:10 + */ + public Boolean updateCardCoupon(String cardId, CardCoupon card) throws WeixinException { + JSONObject request = new JSONObject(); + request.put("card_id", cardId); + CardType cardType = card.getCardType(); + request.put(cardType.name().toLowerCase(), card); + String card_update_uri = getRequestUri("card_update_uri"); + Token token = tokenManager.getCache(); + WeixinResponse response = weixinExecutor.post(String.format(card_update_uri,token.getAccessToken()),JSON.toJSONString(request)); + JSONObject jsonObject= response.getAsJson(); + return jsonObject.getBoolean("send_check"); + } + + + + } diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MemberCardApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MemberCardApi.java new file mode 100644 index 00000000..c3b2e925 --- /dev/null +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MemberCardApi.java @@ -0,0 +1,95 @@ +package com.foxinmy.weixin4j.mp.api; + +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.weixin.ApiResult; +import com.foxinmy.weixin4j.http.weixin.WeixinResponse; +import com.foxinmy.weixin4j.model.Token; +import com.foxinmy.weixin4j.model.card.MemberInitInfo; +import com.foxinmy.weixin4j.model.card.MemberUpdateInfo; +import com.foxinmy.weixin4j.model.card.MemberUserForm; +import com.foxinmy.weixin4j.model.card.MemberUserInfo; +import com.foxinmy.weixin4j.token.TokenManager; + +/** + * 会员卡的api + * + * @auther: Feng Yapeng + * @since: 2016/12/20 14:43 + * @see 创建会员卡&会员卡管理 + */ +public class MemberCardApi extends CardApi { + + + public MemberCardApi(TokenManager tokenManager) { + super(tokenManager); + } + + /** + * 激活方式说明 + * 接口激活通常需要开发者开发用户填写资料的网页。通常有两种激活流程: + * 1. 用户必须在填写资料后才能领卡,领卡后开发者调用激活接口为用户激活会员卡; + * 2. 是用户可以先领取会员卡,点击激活会员卡跳转至开发者设置的资料填写页面,填写完成后开发者调用激活接口为用户激活会员卡。 + * + * @see 接口激活 + */ + public ApiResult activate(MemberInitInfo memberInitInfo) throws WeixinException { + String card_member_card_activate_uri = getRequestUri("card_member_card_activate_uri"); + Token token = tokenManager.getCache(); + WeixinResponse response = weixinExecutor + .post(String.format(card_member_card_activate_uri, token.getAccessToken()), JSON.toJSONString(memberInitInfo)); + return response.getAsResult(); + } + + /** + * 设置开卡字段接口 + * 开发者在创建时填入wx_activate字段后, + * 需要调用该接口设置用户激活时需要填写的选项,否则一键开卡设置不生效。 + * + * @see 一键激活 + */ + public ApiResult setActivateUserForm(MemberUserForm memberUserForm) throws WeixinException { + String user_form_uri = getRequestUri("card_member_card_activate_user_form_uri"); + Token token = tokenManager.getCache(); + WeixinResponse response = weixinExecutor + .post(String.format(user_form_uri, token.getAccessToken()), JSON.toJSONString(memberUserForm)); + return response.getAsResult(); + } + + /** + * 拉取会员信息接口。 + * + * @param cardId the card id + * @param code the code + * @author fengyapeng + * @since 2016 -12-21 11:28:45 + */ + public MemberUserInfo getMemberUserInfo(String cardId, String code) throws WeixinException { + String user_info_uri = getRequestUri("card_member_card_user_info_uri"); + Token token = tokenManager.getCache(); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("card_id", cardId); + jsonObject.put("code", code); + WeixinResponse response = weixinExecutor.post(String.format(user_info_uri, token.getAccessToken()), JSON.toJSONString(jsonObject)); + return response.getAsObject(new TypeReference() { + }); + } + + /** + * 更新会员 + * @param updateInfo + * @return + * @throws WeixinException + */ + public JSONObject updateUserInfo(MemberUpdateInfo updateInfo) throws WeixinException { + String card_member_card_update_user_uri = getRequestUri("card_member_card_update_user_uri"); + Token token = tokenManager.getCache(); + WeixinResponse response = weixinExecutor + .post(String.format(card_member_card_update_user_uri, token.getAccessToken()), JSON.toJSONString(updateInfo)); + return response.getAsJson(); + } + + +} diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties index faf57280..f7550e60 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties @@ -190,11 +190,11 @@ tag_untagging_uri={api_cgi_url}/tags/members/batchuntagging?access_token=%s tag_userids_uri={api_cgi_url}/tags/getidlist?access_token=%s # \u83B7\u53D6\u6807\u7B7E\u4E0B\u7C89\u4E1D\u5217\u8868 tag_user_uri={api_cgi_url}/user/tag/get?access_token=%s -# \u83b7\u53d6\u9ed1\u540d\u5355\u5217\u8868 +# \u83B7\u53D6\u9ED1\u540D\u5355\u5217\u8868 getblacklist_uri={api_cgi_url}/tags/members/getblacklist?access_token=%s -# \u62c9\u9ed1\u7528\u6237 +# \u62C9\u9ED1\u7528\u6237 batchblacklist_uri={api_cgi_url}/tags/members/batchblacklist?access_token=%s -# \u53d6\u6d88\u62c9\u9ed1\u7528\u6237 +# \u53D6\u6D88\u62C9\u9ED1\u7528\u6237 batchunblacklist_uri={api_cgi_url}/tags/members/batchunblacklist?access_token=%s # \u521B\u5EFA\u5361\u5238 @@ -205,6 +205,20 @@ card_paycell_uri={api_base_url}/card/paycell/set?access_token=%s card_selfconsumecell_uri={api_base_url}/card/selfconsumecell/set?access_token=%s # \u521B\u5EFA\u5361\u5238\u4E8C\u7EF4\u7801\u63A5\u53E3 card_qr_ticket_uri={api_base_url}/card/qrcode/create?access_token=%s +# \u4FEE\u6539\u5361\u5238 +card_update_uri={api_base_url}/card/update?access_token=%s +#\u8BBE\u7F6E\u6D4B\u8BD5\u767D\u540D\u5355\u63A5\u53E3 +card_set_test_whitelist_uri={api_base_url}/card/testwhitelist/set?access_token=%s +#\u67E5\u770B\u5361\u5238\u8BE6\u60C5\u63A5\u53E3 +card_get_uri={api_base_url}/card/get?access_token=%s +#\u4F1A\u5458\u5361\u6FC0\u6D3B\u63A5\u53E3 +card_member_card_activate_uri={api_base_url}/card/membercard/activate?access_token=%s +#\u8BBE\u7F6E\u4F1A\u5458\u5361\u5F00\u5361\u5B57\u6BB5 +card_member_card_activate_user_form_uri={api_base_url}/card/membercard/activateuserform/set?access_token=%s +#\u4F1A\u5458\u5361\u7528\u6237\u4FE1\u606F +card_member_card_user_info_uri={api_base_url}/card/membercard/userinfo/get?access_token=%s +#\u66F4\u65B0\u4F1A\u5458\u4FE1\u606F +card_member_card_update_user_uri={api_base_url}/card/membercard/updateuser?access_token=%s # \u4F7F\u7528\u6388\u6743\u7801\u6362\u53D6\u516C\u4F17\u53F7\u7684\u63A5\u53E3\u8C03\u7528\u51ED\u636E\u548C\u6388\u6743\u4FE1\u606F component_exchange_authorizer_uri={api_cgi_url}/component/api_query_auth?component_access_token=%s diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java new file mode 100644 index 00000000..be7d8619 --- /dev/null +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java @@ -0,0 +1,16 @@ +package com.foxinmy.weixin4j.mp.test; + +/** + * 会员卡测试 + * + * @auther: Feng Yapeng + * @since: 2016/12/21 16:37 + */ +public class MemberCardTest extends TokenTest { + + + public void create(){ + + } + +} From ec89112ce669ac7711e85e406043dda9c5ed5a5d Mon Sep 17 00:00:00 2001 From: fengyapeng Date: Thu, 22 Dec 2016 16:58:27 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BC=9A=E5=91=98?= =?UTF-8?q?=E5=8D=A1=E7=9A=84junit=20=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- weixin4j-base/pom.xml | 2 +- .../com/foxinmy/weixin4j/api/BaseApi.java | 5 +- .../foxinmy/weixin4j/http/weixin/error.xml | 2 +- .../weixin4j/model/card/CardCoupons.java | 7 + .../weixin4j/model/card/CouponBaseInfo.java | 10 +- .../weixin4j/model/card/MemberCard.java | 49 ++++--- .../weixin4j/model/card/MemberUserForm.java | 30 ++++- weixin4j-mp/pom.xml | 2 +- .../weixin4j/mp/test/MemberCardTest.java | 122 +++++++++++++++++- weixin4j-qy/pom.xml | 2 +- 11 files changed, 201 insertions(+), 32 deletions(-) diff --git a/pom.xml b/pom.xml index 7ee01f65..8e290ca2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.foxinmy weixin4j - 1.7.3-SNAPSHOT + 1.7.4-SNAPSHOT pom weixin4j https://github.com/foxinmy/weixin4j diff --git a/weixin4j-base/pom.xml b/weixin4j-base/pom.xml index 1457cf0e..35f59332 100644 --- a/weixin4j-base/pom.xml +++ b/weixin4j-base/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.7.3-SNAPSHOT + 1.7.4-SNAPSHOT weixin4j-base weixin4j-base diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java index 5b74b367..10631632 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java @@ -20,6 +20,8 @@ public abstract class BaseApi { protected final WeixinRequestExecutor weixinExecutor; + private final Pattern uriPattern = Pattern.compile("(\\{[^\\}]*\\})"); + public BaseApi() { this.weixinExecutor = new WeixinRequestExecutor(); } @@ -28,8 +30,7 @@ public abstract class BaseApi { protected String getRequestUri(String key) { String url = weixinBundle().getString(key); - Pattern p = Pattern.compile("(\\{[^\\}]*\\})"); - Matcher m = p.matcher(url); + Matcher m = uriPattern.matcher(url); StringBuffer sb = new StringBuffer(); String sub = null; while (m.find()) { diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/error.xml b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/error.xml index aa0ec8d8..81665ba5 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/error.xml +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/error.xml @@ -264,7 +264,7 @@
40073 - 不合法的openid + 不合法的cardid 40074 diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupons.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupons.java index 41508381..dab7f995 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupons.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupons.java @@ -115,4 +115,11 @@ public final class CardCoupons { GrouponCoupon coupon = new GrouponCoupon(couponBaseInfo, explain); return coupon; } + + + public static MemberCard createMemberCard(CouponBaseInfo.Builder baseBuilder, MemberCard.Builder memberCardBudiler) { + baseBuilder.build(); + MemberCard memberCard = new MemberCard(baseBuilder.build(), memberCardBudiler); + return memberCard; + } } \ No newline at end of file diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java index 6933e86e..14b479b9 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java @@ -432,9 +432,13 @@ public class CouponBaseInfo implements Serializable { */ private boolean canGiveFriend; + /** + * 默认永久有效 + */ public Builder() { this.sku = new JSONObject(); this.date = new JSONObject(); + this.date.put("type",CardActiveType.DATE_TYPE_PERMANENT); this.useAllLocation = true; this.canShare = true; this.canGiveFriend = true; @@ -534,6 +538,7 @@ public class CouponBaseInfo implements Serializable { * @return */ public Builder quantity(int quantity) { + quantity = quantity > 100000000 ? 100000000 : quantity; this.sku.put("quantity", quantity); return this; } @@ -807,7 +812,10 @@ public class CouponBaseInfo implements Serializable { /** * 表示固定时长 (自领取后按天算。 */ - DATE_TYPE_FIX_TERM; + DATE_TYPE_FIX_TERM, /** + * 永久有效 + */ + DATE_TYPE_PERMANENT; } } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberCard.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberCard.java index 2cb211fb..3c411df0 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberCard.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberCard.java @@ -53,7 +53,7 @@ public class MemberCard extends CardCoupon { * 显示余额 */ @JSONField(name = "supply_balance") - private String supplyBalance; + private boolean supplyBalance; /** * 设置跳转外链查看余额详情。仅适用于余额无法通过激活接口同步的情况下使用该字段。 */ @@ -134,6 +134,7 @@ public class MemberCard extends CardCoupon { this.bonusRule = builder.bonusRule; } + @JSONField(serialize = false) @Override public CardType getCardType() { return CardType.MEMBER_CARD; @@ -167,7 +168,7 @@ public class MemberCard extends CardCoupon { return bonusUrl; } - public String getSupplyBalance() { + public boolean getSupplyBalance() { return supplyBalance; } @@ -248,7 +249,7 @@ public class MemberCard extends CardCoupon { /** * 显示余额 */ - private String supplyBalance; + private boolean supplyBalance; /** * 设置跳转外链查看余额详情。仅适用于余额无法通过激活接口同步的情况下使用该字段。 */ @@ -291,92 +292,98 @@ public class MemberCard extends CardCoupon { private MemCardBonusRule bonusRule; - public Builder setBackgroundPicUrl(String backgroundPicUrl) { + public Builder backgroundPicUrl(String backgroundPicUrl) { this.backgroundPicUrl = backgroundPicUrl; return this; } - public Builder setPrerogative(String prerogative) { + public Builder prerogative(String prerogative) { this.prerogative = prerogative; return this; } - public Builder setAutoActivate(boolean autoActivate) { + public Builder activateWithAuto(boolean autoActivate) { this.autoActivate = autoActivate; + this.activateUrl = null; + this.wxActivate = false; return this; } - public Builder setWxActivate(boolean wxActivate) { + public Builder activateWithWx(boolean wxActivate) { this.wxActivate = wxActivate; + this.autoActivate = false; + this.activateUrl = null; return this; } - public Builder setActivateUrl(String activateUrl) { + public Builder activateUrl(String activateUrl) { this.activateUrl = activateUrl; + this.autoActivate = false; + this.wxActivate = false; return this; } - public Builder setSupplyBonus(boolean supplyBonus) { + public Builder supplyBonus(boolean supplyBonus) { this.supplyBonus = supplyBonus; return this; } - public Builder setBonusUrl(String bonusUrl) { + public Builder bonusUrl(String bonusUrl) { this.bonusUrl = bonusUrl; return this; } - public Builder setSupplyBalance(String supplyBalance) { + public Builder supplyBalance(boolean supplyBalance) { this.supplyBalance = supplyBalance; return this; } - public Builder setBalanceUrl(String balanceUrl) { + public Builder balanceUrl(String balanceUrl) { this.balanceUrl = balanceUrl; return this; } - public Builder setCustomField1(FieldNameType type, String name, String url) { + public Builder customField1(FieldNameType type, String name, String url) { this.customField1 = new MemCardCustomField(type, name, url); return this; } - public Builder setCustomField2(FieldNameType type, String name, String url) { + public Builder customField2(FieldNameType type, String name, String url) { this.customField2 = new MemCardCustomField(type, name, url); return this; } - public Builder setCustomField3(FieldNameType type, String name, String url) { + public Builder customField3(FieldNameType type, String name, String url) { this.customField3 = new MemCardCustomField(type, name, url); return this; } - public Builder setBonusRules(String bonusRules) { + public Builder bonusRules(String bonusRules) { this.bonusRules = bonusRules; return this; } - public Builder setBalanceRules(String balanceRules) { + public Builder balanceRules(String balanceRules) { this.balanceRules = balanceRules; return this; } - public Builder setBonusCleared(String bonusCleared) { + public Builder bonusCleared(String bonusCleared) { this.bonusCleared = bonusCleared; return this; } - public Builder setCustomCell1(String name, String url, String tips) { + public Builder customCell1(String name, String url, String tips) { this.customCell1 = new MemCardCustomField(name, url, tips); return this; } - public Builder setDiscount(int discount) { + public Builder discount(int discount) { this.discount = discount; return this; } - public Builder setBonusRule(MemCardBonusRule bonusRule) { + public Builder bonusRule(MemCardBonusRule bonusRule) { this.bonusRule = bonusRule; return this; } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUserForm.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUserForm.java index 5dc69e59..efdb31be 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUserForm.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/MemberUserForm.java @@ -84,6 +84,14 @@ public class MemberUserForm { this.optionalForm = formBudiler; } + public FormBudiler getRequiredForm() { + return requiredForm; + } + + public FormBudiler getOptionalForm() { + return optionalForm; + } + public final static class FormBudiler { /** @@ -91,6 +99,7 @@ public class MemberUserForm { * 的字段是否允许用户激活后再次修改,商户设置为true * 时,需要接收相应事件通知处理修改事件 */ + @JSONField(name = "can_modify") private boolean canModify; /** * 自定义富文本类型,包含以下三个字段 @@ -113,7 +122,7 @@ public class MemberUserForm { /** * 自定义富文本类型 */ - private FormBudiler addRichField(ActivateFormFieldType fieldType, String name, String... values) { + public FormBudiler addRichField(ActivateFormFieldType fieldType, String name, String... values) { if (richFieldList == null) { richFieldList = new JSONArray(); } @@ -125,6 +134,12 @@ public class MemberUserForm { return this; } + public FormBudiler canModify(boolean modify){ + this.canModify = canModify; + return this; + } + + /** * 自定义公共字段 */ @@ -152,8 +167,21 @@ public class MemberUserForm { return this; } + public boolean isCanModify() { + return canModify; + } + public JSONArray getRichFieldList() { + return richFieldList; + } + public HashSet getCommonFieldIdList() { + return commonFieldIdList; + } + + public HashSet getCustomFieldList() { + return customFieldList; + } } } diff --git a/weixin4j-mp/pom.xml b/weixin4j-mp/pom.xml index 37a3f242..ff30b420 100644 --- a/weixin4j-mp/pom.xml +++ b/weixin4j-mp/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.7.3-SNAPSHOT + 1.7.4-SNAPSHOT weixin4j-mp weixin4j-mp diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java index be7d8619..89452588 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java @@ -1,16 +1,134 @@ package com.foxinmy.weixin4j.mp.test; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.weixin.ApiResult; +import com.foxinmy.weixin4j.model.card.CardCoupon; +import com.foxinmy.weixin4j.model.card.CardCoupons; +import com.foxinmy.weixin4j.model.card.CardQR; +import com.foxinmy.weixin4j.model.card.CouponBaseInfo; +import com.foxinmy.weixin4j.model.card.MemberCard; +import com.foxinmy.weixin4j.model.card.MemberInitInfo; +import com.foxinmy.weixin4j.model.card.MemberUpdateInfo; +import com.foxinmy.weixin4j.model.card.MemberUserForm; +import com.foxinmy.weixin4j.model.card.MemberUserInfo; +import com.foxinmy.weixin4j.model.qr.QRResult; +import com.foxinmy.weixin4j.mp.api.CardApi; +import com.foxinmy.weixin4j.mp.api.MemberCardApi; +import com.foxinmy.weixin4j.type.card.ActivateCommonField; +import com.foxinmy.weixin4j.type.card.ActivateFormFieldType; +import com.foxinmy.weixin4j.type.card.CardCodeType; +import com.foxinmy.weixin4j.type.card.CardColor; +import com.foxinmy.weixin4j.type.card.FieldNameType; + +import org.junit.Before; +import org.junit.Test; + /** * 会员卡测试 * * @auther: Feng Yapeng * @since: 2016/12/21 16:37 */ -public class MemberCardTest extends TokenTest { +public class MemberCardTest extends TokenTest { + + private CardApi cardApi; + + private MemberCardApi memberCardApi; + + @Before + public void init() { + cardApi = new CardApi(tokenManager); + memberCardApi = new MemberCardApi(tokenManager); + } + + /** + * pn-YDwk59Ft0JSFdGqObxUccUQHw + */ + @Test + public void create() throws WeixinException { + CouponBaseInfo.Builder builder = CardCoupons.customBase(); + // 基础必填字段 + builder.logoUrl( + "http://mmbiz.qpic.cn/mmbiz_jpg/LtkLicv5iclfqzGpaDqDoMibM6FcMVTrmYXjLu7bJ1tM5MzCxNONQiaZHqrYzs0fTk2T5bLAAXLpvx32hQLmJTGBxQ/0") + .codeType(CardCodeType.CODE_TYPE_BARCODE).brandName("***").title("***会员卡").cardColor(CardColor.Color010).notice("请出示会员卡") + .description("***的会员卡的描述").quantity(10000); + // 基础选填字段 + builder.canShare(false).canGiveFriend(false); + builder.centerTitle("卡券居中按钮").centerSubTitle("显示在入口下方的提示语"); + MemberCard.Builder memberCardBuilder = CardCoupons.customMemberCard(); + //会员卡必填字段 + // 会员卡选填字段 + memberCardBuilder.prerogative("会员卡特权说明").supplyBalance(true).supplyBonus(false).activateWithWx(true); + memberCardBuilder.customField1(FieldNameType.FIELD_NAME_TYPE_LEVEL, "等级", null); + memberCardBuilder.backgroundPicUrl( + "https://mmbiz.qlogo.cn/mmbiz/2FyQ9TURqmdibM6nYBiagZT49lSlY9Aicw4P3vsoa7dEZIYfNkiaMyzNVYT9jmYhjBbeC8jnkibwbibB5tghC5XcgysQ/0?wx_fmt=jpeg"); + + MemberCard memberCard = CardCoupons.createMemberCard(builder, memberCardBuilder); + String cardId = memberCardApi.createCardCoupon(memberCard); + System.out.println(cardId); + } - public void create(){ + @Test + public void createCardQR() throws WeixinException { + CardQR.Builder builder = new CardQR.Builder("pn-YDwk59Ft0JSFdGqObxUccUQHw"); + QRResult qrResult = memberCardApi.createCardQR(36000, builder.build()); + String showUrl = qrResult.getShowUrl(); + System.out.println(showUrl); + } + + @Test + public void setMemberUserForm() throws WeixinException { + MemberUserForm memberUserForm = new MemberUserForm(); + memberUserForm.setCardId("pn-YDwk59Ft0JSFdGqObxUccUQHw"); + MemberUserForm.FormBudiler requiredForm = new MemberUserForm.FormBudiler(); + requiredForm.canModify(false); + requiredForm.addCommonField(ActivateCommonField.USER_FORM_INFO_FLAG_EMAIL, ActivateCommonField.USER_FORM_INFO_FLAG_BIRTHDAY, + ActivateCommonField.USER_FORM_INFO_FLAG_MOBILE) + .addRichField(ActivateFormFieldType.FORM_FIELD_CHECK_BOX, "checkBox", "value1", "value2", "value3"); + + memberUserForm.setRequiredForm(requiredForm); + MemberUserForm.FormBudiler optionalFormBuilder = new MemberUserForm.FormBudiler(); + optionalFormBuilder.canModify(false); + optionalFormBuilder.addCommonField(ActivateCommonField.USER_FORM_INFO_FLAG_IDCARD) + .addRichField(ActivateFormFieldType.FORM_FIELD_CHECK_BOX, "checkBoxOPt", "value1", "value2", "value3"); + memberUserForm.setOptionalForm(optionalFormBuilder); + memberUserForm.setServiceStatement("会员守则","https://www.baidu.com"); + ApiResult apiResult = memberCardApi.setActivateUserForm(memberUserForm); + } + + + @Test + public void getMemberUserInfo() throws WeixinException { + MemberUserInfo memberUserInfo = memberCardApi.getMemberUserInfo("pn-YDwk59Ft0JSFdGqObxUccUQHw", "270869833860"); + System.out.println(memberUserInfo); + } + + @Test + public void initMemberUser() throws WeixinException { + MemberInitInfo memberInitInfo = new MemberInitInfo(); + memberInitInfo.setCardId("pn-YDwk59Ft0JSFdGqObxUccUQHw"); + memberInitInfo.setCode("270869833860"); + memberInitInfo.setBackgroundPicUrl("https://mmbiz.qlogo.cn/mmbiz/2FyQ9TURqmdibM6nYBiagZT49lSlY9Aicw4HnSKzouD9iaksVA8vIbFT3RuqnWDVMNZib21NDdwKn5OMVMwfSsULXGw/0?wx_fmt=jpeg"); + memberInitInfo.setInit_custom_field_value1("铂金"); + memberInitInfo.setInitBalance(2); + memberInitInfo.setInitBonus(2); + memberInitInfo.setInitBonusRecord("初始化积分"); + ApiResult activate = memberCardApi.activate(memberInitInfo); + System.out.println(activate); + } + + @Test + public void updateMmemberUser() throws WeixinException { + MemberUpdateInfo memberUpdateInfo = new MemberUpdateInfo(); + memberUpdateInfo.setCardId("pn-YDwk59Ft0JSFdGqObxUccUQHw"); + memberUpdateInfo.setCode("270869833860"); + memberUpdateInfo.setAddBalance(20); + memberUpdateInfo.setRecordBalance("充值"); + memberUpdateInfo.setNOtify(true,true); + memberUpdateInfo.setCustomFieldValue1("至尊铂金",true); + memberCardApi.updateUserInfo(memberUpdateInfo); } } diff --git a/weixin4j-qy/pom.xml b/weixin4j-qy/pom.xml index 893462bc..b10f053e 100644 --- a/weixin4j-qy/pom.xml +++ b/weixin4j-qy/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.7.3-SNAPSHOT + 1.7.4-SNAPSHOT weixin4j-qy weixin4j-qy From 87a2e427deec6ac2643ac1f5f5603ef84b77d389 Mon Sep 17 00:00:00 2001 From: fengyapeng Date: Fri, 23 Dec 2016 17:17:17 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E7=9A=84=E8=BF=94=E5=9B=9E=E5=80=BC=EF=BC=8C?= =?UTF-8?q?=E8=BF=94=E5=9B=9EmsgId=E3=80=82=20=E4=BC=9A=E5=91=98=E5=8D=A1?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=9A=84=E8=B0=83=E6=95=B4=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin4j/model/card/CouponBaseInfo.java | 17 ++++ .../com/foxinmy/weixin4j/mp/WeixinProxy.java | 5 +- .../com/foxinmy/weixin4j/mp/api/CardApi.java | 79 ++++++++++++++- .../weixin4j/mp/api/MemberCardApi.java | 95 ------------------- .../com/foxinmy/weixin4j/mp/api/TmplApi.java | 4 +- .../weixin4j/mp/test/MemberCardTest.java | 20 ++-- 6 files changed, 108 insertions(+), 112 deletions(-) delete mode 100644 weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MemberCardApi.java diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java index 14b479b9..69c73465 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java @@ -581,6 +581,23 @@ public class CouponBaseInfo implements Serializable { return this; } + /** + * 设置卡券在领取多少天后有效 + * + * @param days + * 表示自领取后多少天内有效,不支持填写0。 + * @param beginDays + * 表示自领取后多少天开始生效,领取后当天生效填写0。(单位为天) + * @return + */ + public Builder activeAt(int days, int beginDays) { + this.date.clear(); + this.date.put("type", CardActiveType.DATE_TYPE_FIX_TERM); + this.date.put("fixed_term", days); + this.date.put("fixed_begin_term", beginDays); + return this; + } + /** * 设置是否自定义Code码 * diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java index 57357278..cd1cac07 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java @@ -1005,7 +1005,8 @@ public class WeixinProxy { * 删除群发 * @see com.foxinmy.weixin4j.mp.api.MassApi * @see {@link #massByGroupId(Tuple, int)} - * @see {@link #massByOpenIds(Tuple, String...) + * @see {@link #massByOpenIds(Tuple, String...) + * */ public ApiResult deleteMassNews(String msgid) throws WeixinException { @@ -1570,7 +1571,7 @@ public class WeixinProxy { * @seee com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage * @see com.foxinmy.weixin4j.mp.api.TmplApi */ - public ApiResult sendTmplMessage(TemplateMessage tplMessage) + public String sendTmplMessage(TemplateMessage tplMessage) throws WeixinException { return tmplApi.sendTmplMessage(tplMessage); } diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CardApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CardApi.java index 9d4f17fd..9424eeb4 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CardApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CardApi.java @@ -13,9 +13,14 @@ import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.card.CardCoupon; import com.foxinmy.weixin4j.model.card.CardCoupons; import com.foxinmy.weixin4j.model.card.CardQR; +import com.foxinmy.weixin4j.model.card.MemberInitInfo; +import com.foxinmy.weixin4j.model.card.MemberUpdateInfo; +import com.foxinmy.weixin4j.model.card.MemberUserForm; +import com.foxinmy.weixin4j.model.card.MemberUserInfo; import com.foxinmy.weixin4j.model.qr.QRParameter; import com.foxinmy.weixin4j.model.qr.QRResult; import com.foxinmy.weixin4j.token.TokenManager; +import com.foxinmy.weixin4j.type.card.CardStatus; import com.foxinmy.weixin4j.type.card.CardType; import com.foxinmy.weixin4j.util.IOUtil; @@ -191,7 +196,7 @@ public class CardApi extends MpApi { * @author fengyapeng * @since 2016 -12-20 11:48:23 */ - public void getCardStatus(String cardId) throws WeixinException { + public CardStatus queryCardStatus(String cardId) throws WeixinException { JSONObject requestObj = new JSONObject(); requestObj.put("card_id",cardId); String card_get_uri = getRequestUri("card_get_uri"); @@ -201,7 +206,8 @@ public class CardApi extends MpApi { JSONObject card = responseAsJson.getJSONObject("card"); String cardType = card.getString("card_type"); JSONObject baseInfo = card.getJSONObject(cardType.toLowerCase()).getJSONObject("base_info"); - baseInfo.get("status"); + String status = baseInfo.getString("status"); + return CardStatus.valueOf(status); } /** @@ -230,4 +236,73 @@ public class CardApi extends MpApi { + + /** + * 激活方式说明 + * 接口激活通常需要开发者开发用户填写资料的网页。通常有两种激活流程: + * 1. 用户必须在填写资料后才能领卡,领卡后开发者调用激活接口为用户激活会员卡; + * 2. 是用户可以先领取会员卡,点击激活会员卡跳转至开发者设置的资料填写页面,填写完成后开发者调用激活接口为用户激活会员卡。 + * + * @see 接口激活 + */ + public ApiResult activate(MemberInitInfo memberInitInfo) throws WeixinException { + String card_member_card_activate_uri = getRequestUri("card_member_card_activate_uri"); + Token token = tokenManager.getCache(); + WeixinResponse response = weixinExecutor + .post(String.format(card_member_card_activate_uri, token.getAccessToken()), JSON.toJSONString(memberInitInfo)); + return response.getAsResult(); + } + + /** + * 设置开卡字段接口 + * 开发者在创建时填入wx_activate字段后, + * 需要调用该接口设置用户激活时需要填写的选项,否则一键开卡设置不生效。 + * + * @see 一键激活 + */ + public ApiResult setActivateUserForm(MemberUserForm memberUserForm) throws WeixinException { + String user_form_uri = getRequestUri("card_member_card_activate_user_form_uri"); + Token token = tokenManager.getCache(); + WeixinResponse response = weixinExecutor + .post(String.format(user_form_uri, token.getAccessToken()), JSON.toJSONString(memberUserForm)); + return response.getAsResult(); + } + + /** + * 拉取会员信息接口。 + * + * @param cardId the card id + * @param code the code + * @author fengyapeng + * @since 2016 -12-21 11:28:45 + */ + public MemberUserInfo getMemberUserInfo(String cardId, String code) throws WeixinException { + String user_info_uri = getRequestUri("card_member_card_user_info_uri"); + Token token = tokenManager.getCache(); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("card_id", cardId); + jsonObject.put("code", code); + WeixinResponse response = weixinExecutor.post(String.format(user_info_uri, token.getAccessToken()), JSON.toJSONString(jsonObject)); + return response.getAsObject(new TypeReference() { + }); + } + + /** + * 更新会员 + * @param updateInfo + * @return + * @throws WeixinException + */ + public JSONObject updateUserInfo(MemberUpdateInfo updateInfo) throws WeixinException { + String card_member_card_update_user_uri = getRequestUri("card_member_card_update_user_uri"); + Token token = tokenManager.getCache(); + WeixinResponse response = weixinExecutor + .post(String.format(card_member_card_update_user_uri, token.getAccessToken()), JSON.toJSONString(updateInfo)); + return response.getAsJson(); + } + + + + + } diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MemberCardApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MemberCardApi.java deleted file mode 100644 index c3b2e925..00000000 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MemberCardApi.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.foxinmy.weixin4j.mp.api; - -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.weixin.ApiResult; -import com.foxinmy.weixin4j.http.weixin.WeixinResponse; -import com.foxinmy.weixin4j.model.Token; -import com.foxinmy.weixin4j.model.card.MemberInitInfo; -import com.foxinmy.weixin4j.model.card.MemberUpdateInfo; -import com.foxinmy.weixin4j.model.card.MemberUserForm; -import com.foxinmy.weixin4j.model.card.MemberUserInfo; -import com.foxinmy.weixin4j.token.TokenManager; - -/** - * 会员卡的api - * - * @auther: Feng Yapeng - * @since: 2016/12/20 14:43 - * @see 创建会员卡&会员卡管理 - */ -public class MemberCardApi extends CardApi { - - - public MemberCardApi(TokenManager tokenManager) { - super(tokenManager); - } - - /** - * 激活方式说明 - * 接口激活通常需要开发者开发用户填写资料的网页。通常有两种激活流程: - * 1. 用户必须在填写资料后才能领卡,领卡后开发者调用激活接口为用户激活会员卡; - * 2. 是用户可以先领取会员卡,点击激活会员卡跳转至开发者设置的资料填写页面,填写完成后开发者调用激活接口为用户激活会员卡。 - * - * @see 接口激活 - */ - public ApiResult activate(MemberInitInfo memberInitInfo) throws WeixinException { - String card_member_card_activate_uri = getRequestUri("card_member_card_activate_uri"); - Token token = tokenManager.getCache(); - WeixinResponse response = weixinExecutor - .post(String.format(card_member_card_activate_uri, token.getAccessToken()), JSON.toJSONString(memberInitInfo)); - return response.getAsResult(); - } - - /** - * 设置开卡字段接口 - * 开发者在创建时填入wx_activate字段后, - * 需要调用该接口设置用户激活时需要填写的选项,否则一键开卡设置不生效。 - * - * @see 一键激活 - */ - public ApiResult setActivateUserForm(MemberUserForm memberUserForm) throws WeixinException { - String user_form_uri = getRequestUri("card_member_card_activate_user_form_uri"); - Token token = tokenManager.getCache(); - WeixinResponse response = weixinExecutor - .post(String.format(user_form_uri, token.getAccessToken()), JSON.toJSONString(memberUserForm)); - return response.getAsResult(); - } - - /** - * 拉取会员信息接口。 - * - * @param cardId the card id - * @param code the code - * @author fengyapeng - * @since 2016 -12-21 11:28:45 - */ - public MemberUserInfo getMemberUserInfo(String cardId, String code) throws WeixinException { - String user_info_uri = getRequestUri("card_member_card_user_info_uri"); - Token token = tokenManager.getCache(); - JSONObject jsonObject = new JSONObject(); - jsonObject.put("card_id", cardId); - jsonObject.put("code", code); - WeixinResponse response = weixinExecutor.post(String.format(user_info_uri, token.getAccessToken()), JSON.toJSONString(jsonObject)); - return response.getAsObject(new TypeReference() { - }); - } - - /** - * 更新会员 - * @param updateInfo - * @return - * @throws WeixinException - */ - public JSONObject updateUserInfo(MemberUpdateInfo updateInfo) throws WeixinException { - String card_member_card_update_user_uri = getRequestUri("card_member_card_update_user_uri"); - Token token = tokenManager.getCache(); - WeixinResponse response = weixinExecutor - .post(String.format(card_member_card_update_user_uri, token.getAccessToken()), JSON.toJSONString(updateInfo)); - return response.getAsJson(); - } - - -} diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/TmplApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/TmplApi.java index 726176df..f027efd8 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/TmplApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/TmplApi.java @@ -157,7 +157,7 @@ public class TmplApi extends MpApi { * @see com.foxinmy.weixin4j.mp.message.TemplateMessage * @see com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage */ - public ApiResult sendTmplMessage(TemplateMessage tplMessage) + public String sendTmplMessage(TemplateMessage tplMessage) throws WeixinException { Token token = tokenManager.getCache(); String template_send_uri = getRequestUri("template_send_uri"); @@ -174,6 +174,6 @@ public class TmplApi extends MpApi { } })); - return response.getAsResult(); + return response.getAsJson().getString("msgid"); } } diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java index 89452588..0b4bb3d4 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java @@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.mp.test; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.ApiResult; -import com.foxinmy.weixin4j.model.card.CardCoupon; import com.foxinmy.weixin4j.model.card.CardCoupons; import com.foxinmy.weixin4j.model.card.CardQR; import com.foxinmy.weixin4j.model.card.CouponBaseInfo; @@ -13,7 +12,6 @@ import com.foxinmy.weixin4j.model.card.MemberUserForm; import com.foxinmy.weixin4j.model.card.MemberUserInfo; import com.foxinmy.weixin4j.model.qr.QRResult; import com.foxinmy.weixin4j.mp.api.CardApi; -import com.foxinmy.weixin4j.mp.api.MemberCardApi; import com.foxinmy.weixin4j.type.card.ActivateCommonField; import com.foxinmy.weixin4j.type.card.ActivateFormFieldType; import com.foxinmy.weixin4j.type.card.CardCodeType; @@ -31,14 +29,14 @@ import org.junit.Test; */ public class MemberCardTest extends TokenTest { - private CardApi cardApi; - private MemberCardApi memberCardApi; + + private CardApi cardApi; @Before public void init() { + cardApi = new CardApi(tokenManager); - memberCardApi = new MemberCardApi(tokenManager); } /** @@ -64,7 +62,7 @@ public class MemberCardTest extends TokenTest { "https://mmbiz.qlogo.cn/mmbiz/2FyQ9TURqmdibM6nYBiagZT49lSlY9Aicw4P3vsoa7dEZIYfNkiaMyzNVYT9jmYhjBbeC8jnkibwbibB5tghC5XcgysQ/0?wx_fmt=jpeg"); MemberCard memberCard = CardCoupons.createMemberCard(builder, memberCardBuilder); - String cardId = memberCardApi.createCardCoupon(memberCard); + String cardId = cardApi.createCardCoupon(memberCard); System.out.println(cardId); } @@ -72,7 +70,7 @@ public class MemberCardTest extends TokenTest { @Test public void createCardQR() throws WeixinException { CardQR.Builder builder = new CardQR.Builder("pn-YDwk59Ft0JSFdGqObxUccUQHw"); - QRResult qrResult = memberCardApi.createCardQR(36000, builder.build()); + QRResult qrResult = cardApi.createCardQR(36000, builder.build()); String showUrl = qrResult.getShowUrl(); System.out.println(showUrl); } @@ -95,13 +93,13 @@ public class MemberCardTest extends TokenTest { .addRichField(ActivateFormFieldType.FORM_FIELD_CHECK_BOX, "checkBoxOPt", "value1", "value2", "value3"); memberUserForm.setOptionalForm(optionalFormBuilder); memberUserForm.setServiceStatement("会员守则","https://www.baidu.com"); - ApiResult apiResult = memberCardApi.setActivateUserForm(memberUserForm); + ApiResult apiResult = cardApi.setActivateUserForm(memberUserForm); } @Test public void getMemberUserInfo() throws WeixinException { - MemberUserInfo memberUserInfo = memberCardApi.getMemberUserInfo("pn-YDwk59Ft0JSFdGqObxUccUQHw", "270869833860"); + MemberUserInfo memberUserInfo = cardApi.getMemberUserInfo("pn-YDwk59Ft0JSFdGqObxUccUQHw", "270869833860"); System.out.println(memberUserInfo); } @@ -115,7 +113,7 @@ public class MemberCardTest extends TokenTest { memberInitInfo.setInitBalance(2); memberInitInfo.setInitBonus(2); memberInitInfo.setInitBonusRecord("初始化积分"); - ApiResult activate = memberCardApi.activate(memberInitInfo); + ApiResult activate = cardApi.activate(memberInitInfo); System.out.println(activate); } @@ -128,7 +126,7 @@ public class MemberCardTest extends TokenTest { memberUpdateInfo.setRecordBalance("充值"); memberUpdateInfo.setNOtify(true,true); memberUpdateInfo.setCustomFieldValue1("至尊铂金",true); - memberCardApi.updateUserInfo(memberUpdateInfo); + cardApi.updateUserInfo(memberUpdateInfo); } } From 76f2787f89381dcd2b69d4856afb212b3357dffe Mon Sep 17 00:00:00 2001 From: fengyapeng Date: Mon, 26 Dec 2016 13:18:19 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=8D=A1=E5=88=B8advance?= =?UTF-8?q?d=5Finfo=20=E7=9A=84bug=EF=BC=9B=20=E4=BF=AE=E6=AD=A3=20?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=8D=A1=E5=88=B8=20api=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E6=B8=85=E9=99=A4=E4=B8=8D=E5=8F=AF=E6=9B=B4=E6=94=B9=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E7=9A=84=E5=86=85=E5=AE=B9=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin4j/model/card/CardCoupon.java | 3 ++ .../model/card/CouponAdvanceInfo.java | 45 ++++++++++++++++--- .../weixin4j/model/card/CouponBaseInfo.java | 16 +++++-- .../foxinmy/weixin4j/base/test/PayTest.java | 2 +- .../com/foxinmy/weixin4j/mp/api/CardApi.java | 1 + .../weixin4j/mp/test/MemberCardTest.java | 30 +++++++++++++ 6 files changed, 87 insertions(+), 10 deletions(-) diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupon.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupon.java index eef2fc33..5c37fbf4 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupon.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupon.java @@ -33,6 +33,9 @@ public abstract class CardCoupon { this.couponBaseInfo = couponBaseInfo; } + public void cleanCantUpdateField(){ + this.couponBaseInfo.cleanCantUpdateField(); + } /** * 卡券类型 * diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponAdvanceInfo.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponAdvanceInfo.java index 68505df7..d36f73a5 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponAdvanceInfo.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponAdvanceInfo.java @@ -60,6 +60,27 @@ public class CouponAdvanceInfo implements Serializable { this.businessServices = builder.businessServices; } + + public JSONObject getUseCondition() { + return useCondition; + } + + public JSONObject getAbstractConver() { + return abstractConver; + } + + public List getSlideImages() { + return slideImages; + } + + public List getTimeLimits() { + return timeLimits; + } + + public List getBusinessServices() { + return businessServices; + } + /** * 卡券高级信息构造器 * @@ -91,13 +112,10 @@ public class CouponAdvanceInfo implements Serializable { private List businessServices; public Builder() { - this.useCondition = new JSONObject(); - this.abstractConver = new JSONObject(); - this.slideImages = new ArrayList(); - this.timeLimits = new ArrayList(); - this.businessServices = new ArrayList(); } + + /** * 设置使用门槛(条件)字段,若不填写使用条件则在券面拼写 :无最低消费限制,全场通用,不限品类;并在使用说明显示: 可与其他优惠共享 * @@ -143,6 +161,8 @@ public class CouponAdvanceInfo implements Serializable { public Builder useCondition(String acceptCategory, String rejectCategory, int leastCost, String objectUseFor, boolean canUseWithOtherDiscount) { + if(useCondition == null) + useCondition = new JSONObject(); useCondition.clear(); if (StringUtil.isNotBlank(acceptCategory)) { useCondition.put("accept_category", acceptCategory); @@ -171,6 +191,8 @@ public class CouponAdvanceInfo implements Serializable { * @return */ public Builder abstractConver(String abstracts, String... convers) { + if(abstractConver == null) + abstractConver = new JSONObject(); abstractConver.clear(); abstractConver.put("abstract", abstracts); abstractConver.put("icon_url_list", convers); @@ -185,6 +207,8 @@ public class CouponAdvanceInfo implements Serializable { * @return */ public Builder slideImages(NameValue... slideImages) { + if(this.slideImages == null) + this.slideImages = new ArrayList(); this.slideImages.clear(); for (NameValue nv : slideImages) { JSONObject slide = new JSONObject(); @@ -205,6 +229,8 @@ public class CouponAdvanceInfo implements Serializable { * @return */ public Builder slideImage(String title, String url) { + if(this.slideImages == null) + this.slideImages = new ArrayList(); JSONObject slide = new JSONObject(); slide.put("text", title); slide.put("image_url", url); @@ -250,6 +276,8 @@ public class CouponAdvanceInfo implements Serializable { */ public Builder timeLimit(Week week, int beginHour, int beignMinute, int endHour, int endMinute) { + if(this.timeLimits == null) + this.timeLimits = new ArrayList(); JSONObject timeLimit = new JSONObject(); if (week != null) { timeLimit.put("type", week.name()); @@ -262,6 +290,7 @@ public class CouponAdvanceInfo implements Serializable { if (endMinute > 0) { timeLimit.put("end_minute", endMinute); } + this.timeLimits.add(timeLimit); return this; } @@ -273,9 +302,15 @@ public class CouponAdvanceInfo implements Serializable { * @return */ public Builder businessServices(BusinessService... businessServices) { + if(this.businessServices == null) + this.businessServices = new ArrayList(); this.businessServices.addAll(Arrays.asList(businessServices)); return this; } + + public CouponAdvanceInfo build(){ + return new CouponAdvanceInfo(this); + } } /** diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java index 69c73465..44ef5cda 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java @@ -69,12 +69,12 @@ public class CouponBaseInfo implements Serializable { * 是否自定义Code码 */ @JSONField(name = "use_custom_code") - private boolean useCustomCode; + private Boolean useCustomCode; /** * 指定特殊用户群体 */ @JSONField(name = "bind_openid") - private boolean bindOpenId; + private Boolean bindOpenId; /** * 客服电话 */ @@ -221,11 +221,11 @@ public class CouponBaseInfo implements Serializable { return date; } - public boolean isUseCustomCode() { + public Boolean isUseCustomCode() { return useCustomCode; } - public boolean isBindOpenId() { + public Boolean isBindOpenId() { return bindOpenId; } @@ -312,6 +312,14 @@ public class CouponBaseInfo implements Serializable { + ", canGiveFriend=" + canGiveFriend; } + public void cleanCantUpdateField() { + this.brandName = null; + this.title = null; + this.sku = null; + this.bindOpenId = null; + this.useCustomCode = null; + } + /** * 卡券基础信息构造器 * diff --git a/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/PayTest.java b/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/PayTest.java index 0b5f3e16..1fc30171 100644 --- a/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/PayTest.java +++ b/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/PayTest.java @@ -91,7 +91,7 @@ public class PayTest { c.set(Calendar.DAY_OF_MONTH, 4); System.err.println(c.getTime()); OutputStream os = new FileOutputStream("/tmp/bill20160813.txt"); - PAY.downloadBill(c.getTime(), BillType.ALL, os); + PAY.downloadBill(c.getTime(), BillType.ALL, os,null); } @Test diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CardApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CardApi.java index 9424eeb4..28634596 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CardApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CardApi.java @@ -225,6 +225,7 @@ public class CardApi extends MpApi { JSONObject request = new JSONObject(); request.put("card_id", cardId); CardType cardType = card.getCardType(); + card.cleanCantUpdateField(); request.put(cardType.name().toLowerCase(), card); String card_update_uri = getRequestUri("card_update_uri"); Token token = tokenManager.getCache(); diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java index 0b4bb3d4..8913e4c5 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MemberCardTest.java @@ -4,6 +4,7 @@ import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.ApiResult; import com.foxinmy.weixin4j.model.card.CardCoupons; import com.foxinmy.weixin4j.model.card.CardQR; +import com.foxinmy.weixin4j.model.card.CouponAdvanceInfo; import com.foxinmy.weixin4j.model.card.CouponBaseInfo; import com.foxinmy.weixin4j.model.card.MemberCard; import com.foxinmy.weixin4j.model.card.MemberInitInfo; @@ -129,4 +130,33 @@ public class MemberCardTest extends TokenTest { cardApi.updateUserInfo(memberUpdateInfo); } + + @Test + public void update() throws WeixinException { + CouponBaseInfo.Builder builder = CardCoupons.customBase(); + // 基础必填字段 + builder.logoUrl( + "http://mmbiz.qpic.cn/mmbiz_jpg/LtkLicv5iclfqzGpaDqDoMibM6FcMVTrmYXjLu7bJ1tM5MzCxNONQiaZHqrYzs0fTk2T5bLAAXLpvx32hQLmJTGBxQ/0") + .codeType(CardCodeType.CODE_TYPE_BARCODE).brandName("***").title("***会员卡").cardColor(CardColor.Color010).notice("请出示会员卡") + .description("***的会员卡的描述").quantity(10000); + // 基础选填字段 + builder.canShare(false).canGiveFriend(false); + builder.centerTitle("卡券居中按钮").centerSubTitle("显示在入口下方的提示语"); + MemberCard.Builder memberCardBuilder = CardCoupons.customMemberCard(); + //会员卡必填字段 + // 会员卡选填字段 + memberCardBuilder.prerogative("会员卡特权说明").supplyBalance(true).supplyBonus(false).activateWithWx(true); + memberCardBuilder.customField1(FieldNameType.FIELD_NAME_TYPE_LEVEL, "等级", null); + memberCardBuilder.backgroundPicUrl( + "https://mmbiz.qlogo.cn/mmbiz/2FyQ9TURqmdibM6nYBiagZT49lSlY9Aicw4P3vsoa7dEZIYfNkiaMyzNVYT9jmYhjBbeC8jnkibwbibB5tghC5XcgysQ/0?wx_fmt=jpeg"); + + MemberCard memberCard = CardCoupons.createMemberCard(builder, memberCardBuilder); + CouponAdvanceInfo.Builder advanceBuilder = new CouponAdvanceInfo.Builder(); + advanceBuilder.slideImage("此菜品精选食材,以独特的烹饪方法,最大程度地刺激食 客的味蕾","http://mmbiz.qpic.cn/mmbiz/p98FjXy8LacgHxp3sJ3vn97bGLz0ib0Sfz1bjiaoOYA027iasqSG0sjpiby4vce3AtaPu6cIhBHkt6IjlkY9YnDsfw/0"); + memberCard.setCouponAdvanceInfo(advanceBuilder.build()); + Boolean cardCoupon = cardApi.updateCardCoupon("pn-YDwk59Ft0JSFdGqObxUccUQHw", memberCard); + System.out.println(cardCoupon); + + } + }