From 4c8e33dfac6657dbc2b990d481c5c6b322530b18 Mon Sep 17 00:00:00 2001 From: jinyu Date: Tue, 9 Aug 2016 11:46:37 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AA=92=E4=BD=93=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E8=BD=AC=E6=8D=A2=E9=94=99=E8=AF=AFbug=20&=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=88=9B=E5=BB=BA=E5=8D=A1=E5=88=B8=E4=BA=8C?= =?UTF-8?q?=E7=BB=B4=E7=A0=81=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGE.md | 18 +- weixin4j-base/CHANGE.md | 2 +- .../com/foxinmy/weixin4j/http/MimeType.java | 42 +++-- .../http/weixin/WeixinRequestExecutor.java | 31 +++- .../weixin4j/http/weixin/WeixinResponse.java | 8 +- .../com/foxinmy/weixin4j/model/Button.java | 4 +- .../weixin4j/{ => model}/card/CardCoupon.java | 2 +- .../{ => model}/card/CardCoupons.java | 2 +- .../foxinmy/weixin4j/model/card/CardQR.java | 156 ++++++++++++++++ .../weixin4j/{ => model}/card/CashCoupon.java | 2 +- .../{ => model}/card/CouponAdvanceInfo.java | 2 +- .../{ => model}/card/CouponBaseInfo.java | 2 +- .../{ => model}/card/DiscountCoupon.java | 2 +- .../{ => model}/card/GeneralCoupon.java | 2 +- .../weixin4j/{ => model}/card/GiftCoupon.java | 2 +- .../{ => model}/card/GrouponCoupon.java | 2 +- .../weixin4j/model/qr/QRParameter.java | 173 ++++++++++++++++++ .../foxinmy/weixin4j/model/qr}/QRResult.java | 17 +- .../foxinmy/weixin4j/token/TokenManager.java | 2 +- .../com/foxinmy/weixin4j/type/QRType.java | 10 +- .../com/foxinmy/weixin4j/mp/WeixinProxy.java | 34 +++- .../com/foxinmy/weixin4j/mp/api/CardApi.java | 49 ++++- .../com/foxinmy/weixin4j/mp/api/QrApi.java | 20 +- .../foxinmy/weixin4j/mp/api/weixin.properties | 2 + .../weixin4j/mp/model/QRParameter.java | 139 -------------- .../foxinmy/weixin4j/mp/test/CardTest.java | 6 +- .../foxinmy/weixin4j/mp/test/MenuTest.java | 4 +- .../com/foxinmy/weixin4j/mp/test/QRTest.java | 14 +- .../qy/token/WeixinTicketCreator.java | 7 +- 29 files changed, 551 insertions(+), 205 deletions(-) rename weixin4j-base/src/main/java/com/foxinmy/weixin4j/{ => model}/card/CardCoupon.java (96%) rename weixin4j-base/src/main/java/com/foxinmy/weixin4j/{ => model}/card/CardCoupons.java (98%) create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardQR.java rename weixin4j-base/src/main/java/com/foxinmy/weixin4j/{ => model}/card/CashCoupon.java (97%) rename weixin4j-base/src/main/java/com/foxinmy/weixin4j/{ => model}/card/CouponAdvanceInfo.java (99%) rename weixin4j-base/src/main/java/com/foxinmy/weixin4j/{ => model}/card/CouponBaseInfo.java (99%) rename weixin4j-base/src/main/java/com/foxinmy/weixin4j/{ => model}/card/DiscountCoupon.java (95%) rename weixin4j-base/src/main/java/com/foxinmy/weixin4j/{ => model}/card/GeneralCoupon.java (95%) rename weixin4j-base/src/main/java/com/foxinmy/weixin4j/{ => model}/card/GiftCoupon.java (95%) rename weixin4j-base/src/main/java/com/foxinmy/weixin4j/{ => model}/card/GrouponCoupon.java (96%) create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/qr/QRParameter.java rename {weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model => weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/qr}/QRResult.java (72%) delete mode 100644 weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/QRParameter.java diff --git a/CHANGE.md b/CHANGE.md index 3bffe1a7..a836bfe8 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -737,4 +737,20 @@ + weixin4j-base:主要调整退款相关类与官网一致 - + weixin4j-base:获取cache时加锁处理(via 风车车) \ No newline at end of file + + weixin4j-base:获取cache时加锁处理(via 风车车) + +* 2016-08-05 + + + weixin4j-base:model包拆分media/paging + + + weixin4j-base:type包拆分card/mch + + + weixin4j-base:新增card卡券相关类 + + + weixin4j-mp:新增CardApi:创建卡券接口 + +* 2016-08-09 + + + weixin4j-base:修复媒体消息转换错误bug + + + weixin4j-mp:新增创建卡券二维码接口 \ No newline at end of file diff --git a/weixin4j-base/CHANGE.md b/weixin4j-base/CHANGE.md index 5245e828..3b7b3213 100644 --- a/weixin4j-base/CHANGE.md +++ b/weixin4j-base/CHANGE.md @@ -160,7 +160,7 @@ * 2016-08-05 - + model包拆分media/paing + + model包拆分media/paging + type包拆分card/mch diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/MimeType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/MimeType.java index f23c7e2f..9daa54a9 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/MimeType.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/MimeType.java @@ -1,6 +1,8 @@ package com.foxinmy.weixin4j.http; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; import com.foxinmy.weixin4j.util.StringUtil; @@ -35,12 +37,14 @@ public class MimeType implements Serializable { public static final MimeType TEXT_XML; public static final MimeType TEXT_JSON; + public static final List STREAM_MIMETYPES; + static { APPLICATION_FORM_URLENCODED = valueOf("application/x-www-form-urlencoded"); APPLICATION_JSON = valueOf("application/json"); APPLICATION_OCTET_STREAM = valueOf("application/octet-stream"); APPLICATION_XML = valueOf("application/xml"); - MULTIPART_FORM_DATA = MimeType.valueOf("multipart/form-data"); + MULTIPART_FORM_DATA = valueOf("multipart/form-data"); TEXT_HTML = valueOf("text/html"); TEXT_PLAIN = valueOf("text/plain"); IMAGE_JPG = valueOf("image/jpg"); @@ -48,6 +52,12 @@ public class MimeType implements Serializable { VIDEO_MPEG4 = valueOf("video/mpeg4"); TEXT_XML = valueOf("text/xml"); TEXT_JSON = valueOf("text/json"); + + STREAM_MIMETYPES = new ArrayList(4); + STREAM_MIMETYPES.add(APPLICATION_OCTET_STREAM); + STREAM_MIMETYPES.add(valueOf("image/*")); + STREAM_MIMETYPES.add(valueOf("audio/*")); + STREAM_MIMETYPES.add(valueOf("video/*")); } public MimeType(String type) { @@ -72,28 +82,33 @@ public class MimeType implements Serializable { } public boolean isWildcardSubtype() { - return WILDCARD_TYPE.equals(getSubType()) || getSubType().startsWith("*+"); + return WILDCARD_TYPE.equals(getSubType()) + || getSubType().startsWith("*+"); } public static MimeType valueOf(String value) { if (StringUtil.isBlank(value)) { return null; } - String mimeType = StringUtil.tokenizeToStringArray(value, ";")[0].trim().toLowerCase(Locale.ENGLISH); + String mimeType = StringUtil.tokenizeToStringArray(value, ";")[0] + .trim().toLowerCase(Locale.ENGLISH); if (WILDCARD_TYPE.equals(mimeType)) { mimeType = "*/*"; } int subIndex = mimeType.indexOf('/'); if (subIndex == -1) { - throw new IllegalArgumentException(mimeType + ":does not contain '/'"); + throw new IllegalArgumentException(mimeType + + ":does not contain '/'"); } if (subIndex == mimeType.length() - 1) { - throw new IllegalArgumentException(mimeType + ":does not contain subtype after '/'"); + throw new IllegalArgumentException(mimeType + + ":does not contain subtype after '/'"); } String type = mimeType.substring(0, subIndex); String subType = mimeType.substring(subIndex + 1, mimeType.length()); if (WILDCARD_TYPE.equals(type) && !WILDCARD_TYPE.equals(subType)) { - throw new IllegalArgumentException(mimeType + ":wildcard type is legal only in '*/*' (all mime types)"); + throw new IllegalArgumentException(mimeType + + ":wildcard type is legal only in '*/*' (all mime types)"); } return new MimeType(type, subType); } @@ -121,10 +136,14 @@ public class MimeType implements Serializable { // application/*+xml includes application/soap+xml int otherPlusIdx = other.getSubType().indexOf('+'); if (otherPlusIdx != -1) { - String thisSubtypeNoSuffix = getSubType().substring(0, thisPlusIdx); - String thisSubtypeSuffix = getSubType().substring(thisPlusIdx + 1); - String otherSubtypeSuffix = other.getSubType().substring(otherPlusIdx + 1); - if (thisSubtypeSuffix.equals(otherSubtypeSuffix) && WILDCARD_TYPE.equals(thisSubtypeNoSuffix)) { + String thisSubtypeNoSuffix = getSubType().substring(0, + thisPlusIdx); + String thisSubtypeSuffix = getSubType().substring( + thisPlusIdx + 1); + String otherSubtypeSuffix = other.getSubType() + .substring(otherPlusIdx + 1); + if (thisSubtypeSuffix.equals(otherSubtypeSuffix) + && WILDCARD_TYPE.equals(thisSubtypeNoSuffix)) { return true; } } @@ -148,7 +167,8 @@ public class MimeType implements Serializable { return false; } MimeType otherType = (MimeType) other; - return this.type.equalsIgnoreCase(otherType.type) && this.subType.equalsIgnoreCase(otherType.subType); + return this.type.equalsIgnoreCase(otherType.type) + && this.subType.equalsIgnoreCase(otherType.subType); } @Override 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 c36a3776..eec6d16b 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 @@ -15,6 +15,7 @@ import com.foxinmy.weixin4j.http.HttpMethod; import com.foxinmy.weixin4j.http.HttpParams; import com.foxinmy.weixin4j.http.HttpRequest; import com.foxinmy.weixin4j.http.HttpResponse; +import com.foxinmy.weixin4j.http.MimeType; import com.foxinmy.weixin4j.http.URLParameter; import com.foxinmy.weixin4j.http.apache.FormBodyPart; import com.foxinmy.weixin4j.http.apache.HttpMultipartMode; @@ -129,8 +130,6 @@ public class WeixinRequestExecutor { + request.getURI().toString()); HttpResponse httpResponse = httpClient.execute(request); WeixinResponse response = new WeixinResponse(httpResponse); - logger.info("weixin response << " + httpResponse.getProtocol() - + httpResponse.getStatus() + ":" + response.getAsString()); handleResponse(response); return response; } catch (HttpClientException e) { @@ -138,6 +137,24 @@ public class WeixinRequestExecutor { } } + /** + * 响应内容是否为流 + * + * @param response + * 微信响应 + * @return true/false + */ + private boolean hasStreamMimeType(WeixinResponse response) { + MimeType responseMimeType = MimeType.valueOf(response.getHeaders() + .getContentType()); + for (MimeType streamMimeType : MimeType.STREAM_MIMETYPES) { + if (streamMimeType.includes(responseMimeType)) { + return true; + } + } + return false; + } + /** * handle the weixin response * @@ -147,6 +164,16 @@ public class WeixinRequestExecutor { */ protected void handleResponse(WeixinResponse response) throws WeixinException { + boolean hasStreamMimeType = hasStreamMimeType(response); + logger.info("weixin response << " + + response.getProtocol() + + response.getStatus() + + ":" + + (hasStreamMimeType ? response.getHeaders().getContentType() + : response.getAsString())); + if (hasStreamMimeType) { + return; + } ApiResult result = response.getAsResult(); if (!SUCCESS_CODE.contains(String.format(",%s,", result.getReturnCode() .toLowerCase()))) { diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/WeixinResponse.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/WeixinResponse.java index 572070f0..4e77c596 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/WeixinResponse.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/WeixinResponse.java @@ -5,7 +5,6 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.List; -import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.TypeReference; import com.foxinmy.weixin4j.http.HttpHeaders; @@ -34,6 +33,8 @@ public class WeixinResponse implements HttpResponse { }; private final TypeReference XMLRESULT_CLAZZ = new TypeReference() { }; + private final TypeReference JSONOBJECT_CLAZZ = new TypeReference() { + }; static { messageConverters.add(new JsonMessageConverter()); @@ -56,7 +57,7 @@ public class WeixinResponse implements HttpResponse { } public JSONObject getAsJson() { - return JSON.parseObject(getAsString()); + return getAsObject(JSONOBJECT_CLAZZ); } public XmlResult getAsXml() { @@ -71,7 +72,8 @@ public class WeixinResponse implements HttpResponse { try { return messageConverter.convert(clazz, response); } catch (IOException e) { - throw new RuntimeException("IO error on convert to " + typeReference, e); + throw new RuntimeException("IO error on convert to " + + typeReference, e); } } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Button.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Button.java index 01446871..3666d9e8 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Button.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Button.java @@ -63,7 +63,7 @@ public class Button implements Serializable { } /** - * 创建一个菜单 + * 创建一个具有子菜单的菜单 * * @param name * 菜单名 @@ -76,7 +76,7 @@ public class Button implements Serializable { } /** - * 创建一个菜单 + * 创建一个普通菜单 * * @param name * 菜单名 diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CardCoupon.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupon.java similarity index 96% rename from weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CardCoupon.java rename to weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupon.java index 30641864..eef2fc33 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CardCoupon.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupon.java @@ -1,4 +1,4 @@ -package com.foxinmy.weixin4j.card; +package com.foxinmy.weixin4j.model.card; import com.alibaba.fastjson.annotation.JSONField; import com.foxinmy.weixin4j.type.card.CardType; diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CardCoupons.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupons.java similarity index 98% rename from weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CardCoupons.java rename to weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupons.java index 81c8d024..88c75578 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CardCoupons.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardCoupons.java @@ -1,4 +1,4 @@ -package com.foxinmy.weixin4j.card; +package com.foxinmy.weixin4j.model.card; /** * 卡券构造器 diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardQR.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardQR.java new file mode 100644 index 00000000..138a72ba --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CardQR.java @@ -0,0 +1,156 @@ +package com.foxinmy.weixin4j.model.card; + +import java.io.Serializable; + +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 卡券二维码参数 + * + * @className CardQR + * @author jinyu(foxinmy@gmail.com) + * @date 2016年8月9日 + * @since JDK 1.6 + * @see Builder + */ +public class CardQR implements Serializable { + private static final long serialVersionUID = -2810577326677518511L; + + /** + * 卡券ID + */ + @JSONField(name = "card_id") + private String cardId; + /** + * 卡券Code码,use_custom_code字段为true的卡券必须填写,非自定义code和导入code模式的卡券不必填写。 + */ + @JSONField(name = "code") + private String cardCode; + /** + * 指定领取者的openid,只有该用户能领取。bind_openid字段为true的卡券必须填写,非指定openid不必填写。 + */ + @JSONField(name = "openid") + private String openId; + /** + * 领取场景值,用于领取渠道的数据统计,默认值为0,字段类型为整型,长度限制为60位数字。用户领取卡券后触发的事件推送中会带上此自定义场景值。 + */ + @JSONField(name = "outer_str") + private String sceneValue; + /** + * 指定下发二维码,生成的二维码随机分配一个code,领取后不可再次扫描。填写true或false。默认false,注意填写该字段时, + * 卡券须通过审核且库存不为0。 + */ + @JSONField(name = "is_unique_code") + private boolean isUniqueCode; + + private CardQR(Builder builder) { + this.cardId = builder.cardId; + this.cardCode = builder.cardCode; + this.isUniqueCode = builder.isUniqueCode; + this.openId = builder.openId; + this.sceneValue = builder.sceneValue; + } + + public String getCardId() { + return cardId; + } + + public String getCardCode() { + return cardCode; + } + + public String getOpenId() { + return openId; + } + + public String getSceneValue() { + return sceneValue; + } + + public boolean isUniqueCode() { + return isUniqueCode; + } + + @Override + public String toString() { + return "CardQR [cardId=" + cardId + ", cardCode=" + cardCode + + ", openId=" + openId + ", sceneValue=" + sceneValue + + ", isUniqueCode=" + isUniqueCode + "]"; + } + + public static class Builder { + /** + * 卡券ID + */ + private String cardId; + /** + * 卡券Code码,use_custom_code字段为true的卡券必须填写,非自定义code和导入code模式的卡券不必填写。 + */ + private String cardCode; + /** + * 指定领取者的openid,只有该用户能领取。bind_openid字段为true的卡券必须填写,非指定openid不必填写。 + */ + private String openId; + /** + * 用户首次领卡时,会通过领取事件推送给商户; + * 对于会员卡的二维码,用户每次扫码打开会员卡后点击任何url,会将该值拼入url中,方便开发者定位扫码来源 + */ + private String sceneValue; + /** + * 指定下发二维码,生成的二维码随机分配一个code,领取后不可再次扫描。填写true或false。默认false,注意填写该字段时, + * 卡券须通过审核且库存不为0。 + */ + private boolean isUniqueCode; + + public Builder(String cardId) { + this.cardId = cardId; + } + + /** + * 卡券Code码,use_custom_code字段为true的卡券必须填写,非自定义code和导入code模式的卡券不必填写。 + * + * @param cardCode + * 卡券code码 + */ + public Builder cardCode(String cardCode) { + this.cardCode = cardCode; + return this; + } + + /** + * 指定领取者的openid,只有该用户能领取。bind_openid字段为true的卡券必须填写,非指定openid不必填写。 + * + * @param openId + * 用户openid + */ + public Builder openId(String openId) { + this.openId = openId; + return this; + } + + /** + * 用户首次领卡时,会通过领取事件推送给商户; + * 对于会员卡的二维码,用户每次扫码打开会员卡后点击任何url,会将该值拼入url中,方便开发者定位扫码来源 + * + * @param sceneValue + * 场景值 + */ + public Builder sceneValuer(String sceneValue) { + this.sceneValue = sceneValue; + return this; + } + + /** + * 指定下发二维码,生成的二维码随机分配一个code,领取后不可再次扫描。填写true或false。默认false,注意填写该字段时, + * 卡券须通过审核且库存不为0。 + */ + public Builder openUniqueCode() { + this.isUniqueCode = true; + return this; + } + + public CardQR build() { + return new CardQR(this); + } + } +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CashCoupon.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CashCoupon.java similarity index 97% rename from weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CashCoupon.java rename to weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CashCoupon.java index 251cf59c..d7dd587e 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CashCoupon.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CashCoupon.java @@ -1,4 +1,4 @@ -package com.foxinmy.weixin4j.card; +package com.foxinmy.weixin4j.model.card; import com.alibaba.fastjson.annotation.JSONField; import com.foxinmy.weixin4j.type.card.CardType; diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CouponAdvanceInfo.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponAdvanceInfo.java similarity index 99% rename from weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CouponAdvanceInfo.java rename to weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponAdvanceInfo.java index 5bb673e3..68505df7 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CouponAdvanceInfo.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponAdvanceInfo.java @@ -1,4 +1,4 @@ -package com.foxinmy.weixin4j.card; +package com.foxinmy.weixin4j.model.card; import java.io.Serializable; import java.util.ArrayList; diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CouponBaseInfo.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java similarity index 99% rename from weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CouponBaseInfo.java rename to weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java index a6bf0adb..6933e86e 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/CouponBaseInfo.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/CouponBaseInfo.java @@ -1,4 +1,4 @@ -package com.foxinmy.weixin4j.card; +package com.foxinmy.weixin4j.model.card; import java.io.Serializable; import java.util.Arrays; diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/DiscountCoupon.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/DiscountCoupon.java similarity index 95% rename from weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/DiscountCoupon.java rename to weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/DiscountCoupon.java index 759732d3..eba17a22 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/DiscountCoupon.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/DiscountCoupon.java @@ -1,4 +1,4 @@ -package com.foxinmy.weixin4j.card; +package com.foxinmy.weixin4j.model.card; import com.alibaba.fastjson.annotation.JSONField; import com.foxinmy.weixin4j.type.card.CardType; diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/GeneralCoupon.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/GeneralCoupon.java similarity index 95% rename from weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/GeneralCoupon.java rename to weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/GeneralCoupon.java index 502f0aaf..c200c444 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/GeneralCoupon.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/GeneralCoupon.java @@ -1,4 +1,4 @@ -package com.foxinmy.weixin4j.card; +package com.foxinmy.weixin4j.model.card; import com.alibaba.fastjson.annotation.JSONField; import com.foxinmy.weixin4j.type.card.CardType; diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/GiftCoupon.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/GiftCoupon.java similarity index 95% rename from weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/GiftCoupon.java rename to weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/GiftCoupon.java index bb44053e..77ac29b1 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/GiftCoupon.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/GiftCoupon.java @@ -1,4 +1,4 @@ -package com.foxinmy.weixin4j.card; +package com.foxinmy.weixin4j.model.card; import com.alibaba.fastjson.annotation.JSONField; import com.foxinmy.weixin4j.type.card.CardType; diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/GrouponCoupon.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/GrouponCoupon.java similarity index 96% rename from weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/GrouponCoupon.java rename to weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/GrouponCoupon.java index 7ce32571..86e2c038 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/card/GrouponCoupon.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/card/GrouponCoupon.java @@ -1,4 +1,4 @@ -package com.foxinmy.weixin4j.card; +package com.foxinmy.weixin4j.model.card; import com.alibaba.fastjson.annotation.JSONField; import com.foxinmy.weixin4j.type.card.CardType; diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/qr/QRParameter.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/qr/QRParameter.java new file mode 100644 index 00000000..ae7fbec7 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/qr/QRParameter.java @@ -0,0 +1,173 @@ +package com.foxinmy.weixin4j.model.qr; + +import java.io.Serializable; + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.model.card.CardQR; +import com.foxinmy.weixin4j.type.QRType; + +/** + * 二维码参数对象 + * + * @className QRParameter + * @author jinyu(foxinmy@gmail.com) + * @date 2014年4月8日 + * @since JDK 1.6 + * @see #createTemporaryQR(int, long) 创建整型临时二维码 + * @see #createPermanenceQR(int) 创建整型永久二维码 + * @see #createPermanenceQR(String) 创建字符串型永久二维码 + * @see #createCardCouponQR(Integer, CardQR...) 创建卡券二维码 + */ +public class QRParameter implements Serializable { + + private static final long serialVersionUID = 6611187606558274253L; + + /** + * 二维码的类型 + * + * @see com.foxinmy.weixin4j.type.QRType + */ + @JSONField(name = "action_name") + private QRType qrType; + /** + * 二维码的有效时间 + */ + @JSONField(name = "expire_seconds") + private Integer expireSeconds; + /** + * 二维码的内容 + */ + @JSONField(name = "action_info") + private JSONObject sceneContent; + + private QRParameter(QRType qrType, Integer expireSeconds, + JSONObject sceneContent) { + this.qrType = qrType; + this.expireSeconds = expireSeconds; + this.sceneContent = sceneContent; + } + + public Integer getExpireSeconds() { + return expireSeconds; + } + + public QRType getQrType() { + return qrType; + } + + public JSONObject getSceneContent() { + return sceneContent; + } + + /** + * 创建临时二维码 + * + * @param expireSeconds + * 二维码有效时间,以秒为单位。 最大不超过2592000(即30天) + * @param sceneValue + * 二维码的场景值 临时二维码最大值为无符号32位非0整型 + * @return 二维码参数 + */ + public static QRParameter createTemporaryQR(int expireSeconds, + long sceneValue) { + JSONObject sceneContent = new JSONObject(); + JSONObject scene = new JSONObject(); + scene.put("scene_id", sceneValue); + sceneContent.put("scene", scene); + return new QRParameter(QRType.QR_SCENE, expireSeconds, sceneContent); + } + + /** + * 创建永久二维码(场景值为int) + * + * @param sceneValue + * 场景值 最大值为100000 (目前参数只支持1--100000) + */ + public static QRParameter createPermanenceQR(int sceneValue) { + JSONObject sceneContent = new JSONObject(); + JSONObject scene = new JSONObject(); + scene.put("scene_id", sceneValue); + sceneContent.put("scene", scene); + return new QRParameter(QRType.QR_LIMIT_SCENE, null, sceneContent); + } + + /** + * 创建永久二维码(场景值为string) + * + * @param sceneValue + * 场景值 + */ + public static QRParameter createPermanenceQR(String sceneValue) { + JSONObject sceneContent = new JSONObject(); + JSONObject scene = new JSONObject(); + scene.put("scene_str", sceneValue); + sceneContent.put("scene", scene); + return new QRParameter(QRType.QR_LIMIT_STR_SCENE, null, sceneContent); + } + + /** + * 创建卡券二维码 + * + * @param expireSeconds + * 指定二维码的有效时间,范围是60 ~ 1800秒。不填默认为365天有效 + * @param cardQRs + * 二维码参数:二维码领取单张卡券/多张卡券 + */ + public static QRParameter createCardCouponQR(Integer expireSeconds, + CardQR... cardQRs) { + QRType qrType = QRType.QR_CARD; + JSONObject sceneContent = new JSONObject(); + if (cardQRs.length > 1) { + qrType = QRType.QR_MULTIPLE_CARD; + JSONObject multipleCard = new JSONObject(); + multipleCard.put("card_list", cardQRs); + sceneContent.put("multiple_card", multipleCard); + } else { + sceneContent.put("card", cardQRs[0]); + } + return new QRParameter(qrType, expireSeconds, sceneContent); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((expireSeconds == null) ? 0 : expireSeconds.hashCode()); + result = prime * result + ((qrType == null) ? 0 : qrType.hashCode()); + result = prime * result + + ((sceneContent == null) ? 0 : sceneContent.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + QRParameter other = (QRParameter) obj; + if (expireSeconds == null) { + if (other.expireSeconds != null) + return false; + } else if (!expireSeconds.equals(other.expireSeconds)) + return false; + if (qrType != other.qrType) + return false; + if (sceneContent == null) { + if (other.sceneContent != null) + return false; + } else if (!sceneContent.equals(other.sceneContent)) + return false; + return true; + } + + @Override + public String toString() { + return "QRParameter [qrType=" + qrType + ", expireSeconds=" + + expireSeconds + ", sceneContent=" + sceneContent + "]"; + } +} diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/QRResult.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/qr/QRResult.java similarity index 72% rename from weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/QRResult.java rename to weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/qr/QRResult.java index aa8a6e17..9bf79c62 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/QRResult.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/qr/QRResult.java @@ -1,4 +1,4 @@ -package com.foxinmy.weixin4j.mp.model; +package com.foxinmy.weixin4j.model.qr; import java.io.Serializable; @@ -19,6 +19,8 @@ public class QRResult implements Serializable { private String ticket; private String url; + @JSONField(name = "show_qrcode_url") + private String showUrl; @JSONField(name = "expire_seconds") private int expireSeconds; private byte[] content; @@ -39,6 +41,14 @@ public class QRResult implements Serializable { this.url = url; } + public String getShowUrl() { + return showUrl; + } + + public void setShowUrl(String showUrl) { + this.showUrl = showUrl; + } + public int getExpireSeconds() { return expireSeconds; } @@ -57,7 +67,8 @@ public class QRResult implements Serializable { @Override public String toString() { - return "QRResult [ticket=" + ticket + ", url=" + url - + ", expireSeconds=" + expireSeconds + ", content=...]"; + return "QRResult [ticket=" + ticket + ", url=" + url + ", showUrl=" + + showUrl + ", expireSeconds=" + expireSeconds + + ", content=..." + "]"; } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenManager.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenManager.java index 0e02a86c..44538c57 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenManager.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenManager.java @@ -32,7 +32,7 @@ public class TokenManager extends CacheManager { /** * 获取token字符串 * - * @return + * @return token字符串 * @throws WeixinException */ public String getAccessToken() throws WeixinException { diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/QRType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/QRType.java index cf385a53..f101e7b5 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/QRType.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/QRType.java @@ -21,5 +21,13 @@ public enum QRType { /** * 永久二维码(场景值为字符串长度在1-64之间) */ - QR_LIMIT_STR_SCENE; + QR_LIMIT_STR_SCENE, + /** + * 卡券二维码:单个卡券 + */ + QR_CARD, + /** + * 卡券二维码:多个卡券 + */ + QR_MULTIPLE_CARD; } 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 072c1093..a656ef59 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 @@ -4,18 +4,21 @@ import java.io.InputStream; import java.util.Date; import java.util.List; -import com.foxinmy.weixin4j.card.CardCoupon; -import com.foxinmy.weixin4j.card.CardCoupons; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.ApiResult; import com.foxinmy.weixin4j.model.Button; import com.foxinmy.weixin4j.model.WeixinAccount; +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.media.MediaCounter; import com.foxinmy.weixin4j.model.media.MediaDownloadResult; import com.foxinmy.weixin4j.model.media.MediaItem; import com.foxinmy.weixin4j.model.media.MediaRecord; import com.foxinmy.weixin4j.model.media.MediaUploadResult; import com.foxinmy.weixin4j.model.paging.Pageable; +import com.foxinmy.weixin4j.model.qr.QRParameter; +import com.foxinmy.weixin4j.model.qr.QRResult; import com.foxinmy.weixin4j.mp.api.CardApi; import com.foxinmy.weixin4j.mp.api.CustomApi; import com.foxinmy.weixin4j.mp.api.DataApi; @@ -43,8 +46,6 @@ import com.foxinmy.weixin4j.mp.model.KfSession.KfSessionCounter; import com.foxinmy.weixin4j.mp.model.Menu; import com.foxinmy.weixin4j.mp.model.MenuMatchRule; import com.foxinmy.weixin4j.mp.model.MenuSetting; -import com.foxinmy.weixin4j.mp.model.QRParameter; -import com.foxinmy.weixin4j.mp.model.QRResult; import com.foxinmy.weixin4j.mp.model.SemQuery; import com.foxinmy.weixin4j.mp.model.SemResult; import com.foxinmy.weixin4j.mp.model.Tag; @@ -176,6 +177,7 @@ public class WeixinProxy { componentTokenManager), perTicketManager.getCacheStorager())); this.settings = new Weixin4jSettings(new WeixinAccount( perTicketManager.getAuthAppId(), null)); + this.settings.setCacheStorager(perTicketManager.getCacheStorager()); } /** @@ -1376,8 +1378,8 @@ public class WeixinProxy { * 二维码参数 * @return 二维码结果对象 * @throws WeixinException - * @see com.foxinmy.weixin4j.mp.model.QRResult - * @see com.foxinmy.weixin4j.mp.model.QRParameter + * @see com.foxinmy.weixin4j.model.qr.QRResult + * @see com.foxinmy.weixin4j.model.qr.QRParameter * @see com.foxinmy.weixin4j.mp.api.QrApi * @see @@ -1904,5 +1906,25 @@ public class WeixinProxy { return cardApi.setCardSelfConsumeCell(cardId, isOpen); } + /** + * 创建卡券二维码: 开发者可调用该接口生成一张卡券二维码供用户扫码后添加卡券到卡包。 + * + * @param expireSeconds + * 指定二维码的有效时间,范围是60 ~ 1800秒。不填默认为365天有效 + * @param cardQRs + * 二维码参数:二维码领取单张卡券/多张卡券 + * @return 二维码结果对象 + * @see com.foxinmy.weixin4j.model.qr.QRResult + * @see com.foxinmy.weixin4j.model.qr.QRParameter + * @see com.foxinmy.weixin4j.mp.api.CardApi + * @see 投放卡券 + * @throws WeixinException + */ + public QRResult createCardQR(Integer expireSeconds, CardQR... cardQRs) + throws WeixinException { + return cardApi.createCardQR(expireSeconds, cardQRs); + } + public final static String VERSION = "1.7.0"; } 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 d5e5935f..086833a8 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,13 +1,21 @@ package com.foxinmy.weixin4j.mp.api; +import java.io.IOException; + +import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; -import com.foxinmy.weixin4j.card.CardCoupon; -import com.foxinmy.weixin4j.card.CardCoupons; +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.CardCoupon; +import com.foxinmy.weixin4j.model.card.CardCoupons; +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.util.IOUtil; /** * 卡券API @@ -111,4 +119,41 @@ public class CardApi extends MpApi { token.getAccessToken()), params.toJSONString()); return response.getAsResult(); } + + /** + * 创建卡券二维码: 开发者可调用该接口生成一张卡券二维码供用户扫码后添加卡券到卡包。 + * + * @param expireSeconds + * 指定二维码的有效时间,范围是60 ~ 1800秒。不填默认为365天有效 + * @param cardQRs + * 二维码参数:二维码领取单张卡券/多张卡券 + * @return 二维码结果对象 + * @see com.foxinmy.weixin4j.model.qr.QRResult + * @see com.foxinmy.weixin4j.model.qr.QRParameter + * @see 投放卡券 + * @throws WeixinException + */ + public QRResult createCardQR(Integer expireSeconds, CardQR... cardQRs) + throws WeixinException { + QRParameter parameter = QRParameter.createCardCouponQR(expireSeconds, + cardQRs); + Token token = tokenManager.getCache(); + String qr_uri = getRequestUri("card_qr_ticket_uri"); + WeixinResponse response = weixinExecutor.post( + String.format(qr_uri, token.getAccessToken()), + JSON.toJSONString(parameter)); + QRResult result = response.getAsObject(new TypeReference() { + }); + qr_uri = String.format(getRequestUri("qr_image_uri"), + result.getTicket()); + response = weixinExecutor.get(qr_uri); + result.setShowUrl(qr_uri); + try { + result.setContent(IOUtil.toByteArray(response.getBody())); + } catch (IOException e) { + throw new WeixinException(e); + } + return result; + } } diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java index 299d5541..d3f6af46 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java @@ -1,13 +1,14 @@ - package com.foxinmy.weixin4j.mp.api; +package com.foxinmy.weixin4j.mp.api; import java.io.IOException; +import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.model.Token; -import com.foxinmy.weixin4j.mp.model.QRParameter; -import com.foxinmy.weixin4j.mp.model.QRResult; +import com.foxinmy.weixin4j.model.qr.QRParameter; +import com.foxinmy.weixin4j.model.qr.QRResult; import com.foxinmy.weixin4j.token.TokenManager; import com.foxinmy.weixin4j.util.IOUtil; @@ -34,8 +35,8 @@ public class QrApi extends MpApi { * 二维码参数 * @return 二维码结果对象 * @throws WeixinException - * @see com.foxinmy.weixin4j.mp.model.QRResult - * @see com.foxinmy.weixin4j.mp.model.QRParameter + * @see com.foxinmy.weixin4j.model.qr.QRResult + * @see com.foxinmy.weixin4j.model.qr.QRParameter * @see 生成二维码 */ @@ -44,12 +45,13 @@ public class QrApi extends MpApi { String qr_uri = getRequestUri("qr_ticket_uri"); WeixinResponse response = weixinExecutor.post( String.format(qr_uri, token.getAccessToken()), - parameter.getContent()); + JSON.toJSONString(parameter)); QRResult result = response.getAsObject(new TypeReference() { }); - qr_uri = getRequestUri("qr_image_uri"); - response = weixinExecutor - .get(String.format(qr_uri, result.getTicket())); + qr_uri = String.format(getRequestUri("qr_image_uri"), + result.getTicket()); + response = weixinExecutor.get(qr_uri); + result.setShowUrl(qr_uri); try { result.setContent(IOUtil.toByteArray(response.getBody())); } catch (IOException e) { 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 e7e993bf..7968a3a7 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 @@ -186,6 +186,8 @@ card_create_uri={api_base_url}/card/create?access_token=%s card_paycell_uri={api_base_url}/card/paycell/set?access_token=%s # \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 +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 component_exchange_authorizer_uri={api_cgi_url}/component/api_query_auth?component_access_token=%s diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/QRParameter.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/QRParameter.java deleted file mode 100644 index 98c0f35f..00000000 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/QRParameter.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.foxinmy.weixin4j.mp.model; - -import java.io.Serializable; - -import com.foxinmy.weixin4j.type.QRType; - -/** - * 二维码参数对象 - *

- * 目前有2种类型的二维码,分别是临时二维码和永久二维码,前者有过期时间,最大为1800秒,但能够生成较多数量,后者无过期时间,数量较少(目前参数只支持1-- - * 100000) - *

- * - * @className QRParameter - * @author jinyu(foxinmy@gmail.com) - * @date 2014年4月8日 - * @since JDK 1.6 - * @see #createPermanenceInt(int) 创建整型永久二维码 - * @see #createPermanenceStr(String) 创建字符串型永久二维码 - * @see #createTemporary(long) 创建整型默认30秒有效期临时二维码 - * @see #createTemporary(int, long) 创建整型有效期临时二维码 - */ -public class QRParameter implements Serializable { - - private static final long serialVersionUID = 6611187606558274253L; - private static final int DEFAULT_TEMPORARY_EXPIRE_SECONDS = 30; - - /** - * 临时二维码的有效时间, 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒 - */ - private int expireSeconds; - /** - * 二维码类型 - * - * @see com.foxinmy.weixin4j.type.QRType - */ - private QRType qrType; - /** - * 场景值I 根据qrType参数而定 - */ - private String sceneValue; - - private QRParameter() { - } - - public int getExpireSeconds() { - return expireSeconds; - } - - public QRType getQrType() { - return qrType; - } - - public String getSceneValue() { - return sceneValue; - } - - private String content; - - public String getContent() { - return content; - } - - /** - * 创建临时二维码 - * - * @param expireSeconds - * 有效时间 - * @param sceneValue - * 二维码的场景值 临时二维码最大值为无符号32位非0整型 - * @return 二维码参数 - */ - public static QRParameter createTemporary(int expireSeconds, long sceneValue) { - QRParameter qr = new QRParameter(); - qr.qrType = QRType.QR_SCENE; - qr.expireSeconds = expireSeconds; - qr.sceneValue = Long.toString(sceneValue); - qr.content = String.format( - "{\"expire_seconds\": %s, \"action_name\": \"%s\", \"action_info\": {\"scene\": {\"scene_id\": %s}}}", - expireSeconds, QRType.QR_SCENE.name(), sceneValue); - return qr; - } - - /** - * 创建临时二维码(默认有效期为30秒) - * - * @param sceneValue - * 二维码的场景值 临时二维码最大值为无符号32位非0整型 - * @return 二维码参数 - */ - public static QRParameter createTemporary(long sceneValue) { - QRParameter qr = new QRParameter(); - qr.qrType = QRType.QR_SCENE; - qr.expireSeconds = DEFAULT_TEMPORARY_EXPIRE_SECONDS; - qr.sceneValue = Long.toString(sceneValue); - qr.content = String.format( - "{\"expire_seconds\": %s, \"action_name\": \"%s\", \"action_info\": {\"scene\": {\"scene_id\": %s}}}", - DEFAULT_TEMPORARY_EXPIRE_SECONDS, QRType.QR_SCENE.name(), sceneValue); - return qr; - } - - /** - * 创建永久二维码(场景值为int) - * - * @param sceneValue - * 场景值 最大值为100000 - * @return 二维码参数 - */ - public static QRParameter createPermanenceInt(int sceneValue) { - QRParameter qr = new QRParameter(); - qr.qrType = QRType.QR_LIMIT_SCENE; - qr.sceneValue = Integer.toString(sceneValue); - qr.content = String.format("{\"action_name\": \"%s\", \"action_info\": {\"scene\": {\"scene_id\": %s}}}", - QRType.QR_LIMIT_SCENE.name(), sceneValue); - return qr; - } - - /** - * 创建永久二维码(场景值为string) - * - * @param sceneValue - * 场景值 - * @return 二维码参数 - */ - public static QRParameter createPermanenceStr(String sceneValue) { - QRParameter qr = new QRParameter(); - qr.qrType = QRType.QR_LIMIT_STR_SCENE; - qr.sceneValue = sceneValue; - qr.content = String.format("{\"action_name\": \"%s\", \"action_info\": {\"scene\": {\"scene_str\": \"%s\"}}}", - QRType.QR_LIMIT_STR_SCENE, sceneValue); - return qr; - } - - @Override - public String toString() { - return "QRParameter [expireSeconds=" + expireSeconds + ", qrType=" + qrType + ", sceneValue=" + sceneValue - + "]"; - } -} diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/CardTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/CardTest.java index e646558b..eca1abab 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/CardTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/CardTest.java @@ -7,10 +7,10 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import com.foxinmy.weixin4j.card.CardCoupon; -import com.foxinmy.weixin4j.card.CardCoupons; -import com.foxinmy.weixin4j.card.CouponBaseInfo; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.model.card.CardCoupon; +import com.foxinmy.weixin4j.model.card.CardCoupons; +import com.foxinmy.weixin4j.model.card.CouponBaseInfo; import com.foxinmy.weixin4j.mp.api.CardApi; import com.foxinmy.weixin4j.type.card.CardCodeType; import com.foxinmy.weixin4j.type.card.CardColor; diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MenuTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MenuTest.java index b5cd9d3b..fac450ec 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MenuTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MenuTest.java @@ -40,7 +40,7 @@ public class MenuTest extends TokenTest { String domain = "http://wx.jdxg.doubimeizhi.com"; buttons.add(new Button("立即下单", domain, ButtonType.view)); - buttons.add(new Button("个人中心", domain + "/user", ButtonType.view)); + //buttons.add(new Button("个人中心", domain + "/user", ButtonType.view)); Button button = new Button("小哥介绍", domain, ButtonType.view); button.pushSub(new Button("小哥介绍", "http://x.eqxiu.com/s/89oy462U", @@ -52,7 +52,7 @@ public class MenuTest extends TokenTest { ButtonType.view)); button.pushSub(new Button("服务流程", "FLOW", ButtonType.click)); button.pushSub(new Button("在线客服", "KF", ButtonType.click)); - buttons.add(button); + //buttons.add(button); ApiResult result = menuApi.createMenu(buttons); Assert.assertEquals("0", result.getReturnCode()); diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/QRTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/QRTest.java index 1d63e11f..769e4b8f 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/QRTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/QRTest.java @@ -7,9 +7,9 @@ import org.junit.Before; import org.junit.Test; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.model.qr.QRParameter; +import com.foxinmy.weixin4j.model.qr.QRResult; import com.foxinmy.weixin4j.mp.api.QrApi; -import com.foxinmy.weixin4j.mp.model.QRParameter; -import com.foxinmy.weixin4j.mp.model.QRResult; /** * 二维码相关测试 @@ -23,27 +23,27 @@ public class QRTest extends TokenTest { private QrApi qrApi; @Before - public void init() { + public void init() throws WeixinException { qrApi = new QrApi(tokenManager); } @Test public void temp_qr() throws WeixinException, IOException { - QRResult result = qrApi.createQR(QRParameter - .createTemporary(1200, 1200)); + QRResult result = qrApi.createQR(QRParameter.createTemporaryQR(1200, + 1200L)); Assert.assertTrue(!result.getTicket().isEmpty()); } @Test public void forever_qr_int() throws WeixinException, IOException { - QRResult result = qrApi.createQR(QRParameter.createPermanenceInt(2)); + QRResult result = qrApi.createQR(QRParameter.createPermanenceQR(2)); Assert.assertTrue(!result.getTicket().isEmpty()); } @Test public void forever_qr_str() throws WeixinException, IOException { QRResult result = qrApi.createQR(QRParameter - .createPermanenceStr("1200中文")); + .createPermanenceQR("1200中文")); Assert.assertTrue(!result.getTicket().isEmpty()); } } diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTicketCreator.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTicketCreator.java index 665d268a..ac080288 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTicketCreator.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTicketCreator.java @@ -15,9 +15,10 @@ import com.foxinmy.weixin4j.type.TicketType; * @className WeixinTicketCreator * @author jinyu(foxinmy@gmail.com) * @date 2015年12月25日 - * @since JDK 1.6 JSTICKET + * @since JDK 1.6 + * @see JSTICKET */ public class WeixinTicketCreator extends TokenCreator {