diff --git a/pom.xml b/pom.xml index 9047dab6..7cbd7116 100644 --- a/pom.xml +++ b/pom.xml @@ -6,10 +6,10 @@ 4.0.0 com.github.binarywang weixin-java-parent - 3.1.0 + 3.2.0 pom Weixin Java Tools - Parent - 微信公众号、企业号上级POM + 微信开发Java SDK https://github.com/wechat-group/weixin-java-tools diff --git a/qrcodes/cp_qrcode.png b/qrcodes/cp_qrcode.png new file mode 100644 index 00000000..468369a8 Binary files /dev/null and b/qrcodes/cp_qrcode.png differ diff --git a/qrcodes/mp_qrcode.jpg b/qrcodes/mp_qrcode.jpg new file mode 100644 index 00000000..b5b0dc6f Binary files /dev/null and b/qrcodes/mp_qrcode.jpg differ diff --git a/qrcodes/wepay_qrcode_s.jpg b/qrcodes/wepay_qrcode_s.jpg new file mode 100644 index 00000000..da8d1e03 Binary files /dev/null and b/qrcodes/wepay_qrcode_s.jpg differ diff --git a/quality-checks/google_checks.xml b/quality-checks/google_checks.xml index 654e7cc8..b1b2a46f 100644 --- a/quality-checks/google_checks.xml +++ b/quality-checks/google_checks.xml @@ -83,20 +83,6 @@ - - - - - - - - - - - - - - + value="SPECIAL_IMPORTS###STANDARD_JAVA_PACKAGE###THIRD_PARTY_PACKAGE###STATIC"/> diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index ff91458c..c1bfa3bc 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -7,12 +7,12 @@ com.github.binarywang weixin-java-parent - 3.1.0 + 3.2.0 weixin-java-common Weixin Java Tools - Common - 微信公众号、企业号Java SDK Common + 微信开发Java SDK公共模块 diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java index 9704f037..a1e3c073 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java @@ -6,7 +6,7 @@ import java.util.Map; /** * 微信开发所使用到的常量类. * - * @author chanjarster & binarywang + * @author Daniel Qian & binarywang */ public class WxConsts { /** @@ -82,7 +82,7 @@ public class WxConsts { /** * 小程序卡片(要求小程序与公众号已关联) */ - public static final String MINIPROGRAMPAGE="miniprogrampage"; + public static final String MINIPROGRAMPAGE = "miniprogrampage"; } /** @@ -151,14 +151,106 @@ public class WxConsts { public static final String CLICK = "CLICK"; public static final String VIEW = "VIEW"; public static final String MASS_SEND_JOB_FINISH = "MASSSENDJOBFINISH"; + /** + * 扫码推事件的事件推送 + */ public static final String SCANCODE_PUSH = "scancode_push"; + /** + * 扫码推事件且弹出“消息接收中”提示框的事件推送. + */ public static final String SCANCODE_WAITMSG = "scancode_waitmsg"; + /** + * 弹出系统拍照发图的事件推送. + */ public static final String PIC_SYSPHOTO = "pic_sysphoto"; + /** + * 弹出拍照或者相册发图的事件推送. + */ public static final String PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; + /** + * 弹出微信相册发图器的事件推送. + */ public static final String PIC_WEIXIN = "pic_weixin"; + /** + * 弹出地理位置选择器的事件推送. + */ public static final String LOCATION_SELECT = "location_select"; + public static final String TEMPLATE_SEND_JOB_FINISH = "TEMPLATESENDJOBFINISH"; - public static final String ENTER_AGENT = "enter_agent"; + /** + * 微信小店 订单付款通知. + */ + public static final String MERCHANT_ORDER = "merchant_order"; + + /** + * 卡券事件:卡券通过审核 + */ + public static final String CARD_PASS_CHECK = "card_pass_check"; + + /** + * 卡券事件:卡券未通过审核 + */ + public static final String CARD_NOT_PASS_CHECK = "card_not_pass_check"; + + /** + * 卡券事件:用户领取卡券 + */ + public static final String CARD_USER_GET_CARD = "user_get_card"; + + /** + * 卡券事件:用户转赠卡券 + */ + public static final String CARD_USER_GIFTING_CARD = "user_gifting_card"; + + + /** + * 卡券事件:用户核销卡券 + */ + public static final String CARD_USER_CONSUME_CARD = "user_consume_card"; + + + /** + * 卡券事件:用户通过卡券的微信买单完成时推送 + */ + public static final String CARD_USER_PAY_FROM_PAY_CELL = "user_pay_from_pay_cell"; + + + /** + * 卡券事件:用户提交会员卡开卡信息 + */ + public static final String CARD_SUBMIT_MEMBERCARD_USER_INFO = "submit_membercard_user_info"; + + /** + * 卡券事件:用户打开查看卡券 + */ + public static final String CARD_USER_VIEW_CARD = "user_view_card"; + + /** + * 卡券事件:用户删除卡券 + */ + public static final String CARD_USER_DEL_CARD = "user_del_card"; + + /** + * 卡券事件:用户在卡券里点击查看公众号进入会话时(需要用户已经关注公众号) + */ + public static final String CARD_USER_ENTER_SESSION_FROM_CARD = "user_enter_session_from_card"; + + /** + * 卡券事件:当用户的会员卡积分余额发生变动时 + */ + public static final String CARD_UPDATE_MEMBER_CARD = "update_member_card"; + + /** + * 卡券事件:当某个card_id的初始库存数大于200且当前库存小于等于100时,用户尝试领券会触发发送事件给商户,事件每隔12h发送一次 + */ + public static final String CARD_SKU_REMIND = "card_sku_remind"; + + /** + * 卡券事件:当商户朋友的券券点发生变动时 + */ + public static final String CARD_PAY_ORDER = "card_pay_order"; + + } /** @@ -230,10 +322,16 @@ public class WxConsts { * 不弹出授权页面,直接跳转,只能获取用户openid. */ public static final String SNSAPI_BASE = "snsapi_base"; + /** * 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息. */ public static final String SNSAPI_USERINFO = "snsapi_userinfo"; + + /** + * 手动授权,可获取成员的详细信息,包含手机、邮箱。只适用于企业微信或企业号. + */ + public static final String SNSAPI_PRIVATEINFO = "snsapi_privateinfo"; } /** @@ -252,4 +350,5 @@ public class WxConsts { public static final String IMAGE = "image"; public static final String VIDEO = "video"; } + } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxErrorExceptionHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxErrorExceptionHandler.java index 7a452df6..83242e2f 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxErrorExceptionHandler.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxErrorExceptionHandler.java @@ -4,6 +4,8 @@ import me.chanjar.weixin.common.error.WxErrorException; /** * WxErrorException处理器. + * + * @author Daniel Qian */ public interface WxErrorExceptionHandler { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageDuplicateChecker.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageDuplicateChecker.java index fdb0cd81..3993dab5 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageDuplicateChecker.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageDuplicateChecker.java @@ -5,6 +5,8 @@ package me.chanjar.weixin.common.api; * 消息重复检查器. * 微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次 * + * + * @author Daniel Qian */ public interface WxMessageDuplicateChecker { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java index d8be08f4..c0f57c83 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java @@ -9,6 +9,8 @@ import java.util.concurrent.atomic.AtomicBoolean; * 默认消息重复检查器. * 将每个消息id保存在内存里,每隔5秒清理已经过期的消息id,每个消息id的过期时间是15秒 * + * + * @author Daniel Qian */ public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChecker { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxAccessToken.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxAccessToken.java index 63279651..3935e5f5 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxAccessToken.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxAccessToken.java @@ -1,10 +1,15 @@ package me.chanjar.weixin.common.bean; +import java.io.Serializable; + import lombok.Data; import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import java.io.Serializable; - +/** + * access token. + * + * @author Daniel Qian + */ @Data public class WxAccessToken implements Serializable { private static final long serialVersionUID = 8709719312922168909L; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxCardApiSignature.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxCardApiSignature.java index 9d5d7a06..17d8ab9f 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxCardApiSignature.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxCardApiSignature.java @@ -1,10 +1,12 @@ package me.chanjar.weixin.common.bean; -import lombok.Data; -import me.chanjar.weixin.common.util.ToStringUtils; - import java.io.Serializable; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import lombok.Data; + /** * 卡券Api签名. * @@ -35,7 +37,6 @@ public class WxCardApiSignature implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } - } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxJsapiSignature.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxJsapiSignature.java index 619f0a75..759f5e12 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxJsapiSignature.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxJsapiSignature.java @@ -1,13 +1,21 @@ package me.chanjar.weixin.common.bean; -import lombok.Data; - import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + /** * jspai signature. + * + * @author Daniel Qian */ @Data +@Builder +@NoArgsConstructor +@AllArgsConstructor public class WxJsapiSignature implements Serializable { private static final long serialVersionUID = -1116808193154384804L; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenu.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenu.java index 4d349acb..8b43646a 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenu.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenu.java @@ -1,9 +1,5 @@ package me.chanjar.weixin.common.bean.menu; -import lombok.Data; -import me.chanjar.weixin.common.util.ToStringUtils; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; - import java.io.InputStream; import java.io.InputStreamReader; import java.io.Serializable; @@ -11,6 +7,12 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import lombok.Data; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + /** * 菜单(公众号和企业号共用的). * @@ -47,7 +49,7 @@ public class WxMenu implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuButton.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuButton.java index 2f9276b0..5e0b9db9 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuButton.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuButton.java @@ -1,13 +1,20 @@ package me.chanjar.weixin.common.bean.menu; -import com.google.gson.annotations.SerializedName; -import lombok.Data; -import me.chanjar.weixin.common.util.ToStringUtils; - import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +/** + * menu button. + * + * @author Daniel Qian + */ @Data public class WxMenuButton implements Serializable { private static final long serialVersionUID = -1070939403109776555L; @@ -76,7 +83,7 @@ public class WxMenuButton implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuRule.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuRule.java index 16542dec..632279b9 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuRule.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuRule.java @@ -1,11 +1,18 @@ package me.chanjar.weixin.common.bean.menu; +import java.io.Serializable; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import com.google.gson.annotations.SerializedName; import lombok.Data; -import me.chanjar.weixin.common.util.ToStringUtils; - -import java.io.Serializable; +/** + * menu rule. + * + * @author Daniel Qian + */ @Data public class WxMenuRule implements Serializable { private static final long serialVersionUID = -4587181819499286670L; @@ -24,6 +31,6 @@ public class WxMenuRule implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java index a50018aa..d6ffd50c 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java @@ -1,15 +1,22 @@ package me.chanjar.weixin.common.bean.result; +import java.io.Serializable; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import lombok.Data; -import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import java.io.Serializable; - +/** + * + * @author Daniel Qian + */ @Data public class WxMediaUploadResult implements Serializable { private static final long serialVersionUID = 330834334738622341L; + private String url; private String type; private String mediaId; private String thumbMediaId; @@ -21,7 +28,7 @@ public class WxMediaUploadResult implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSession.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSession.java index 77d4d282..05cb4136 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSession.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSession.java @@ -1,5 +1,9 @@ package me.chanjar.weixin.common.session; +/** + * + * @author Daniel Qian + */ public interface InternalSession { /** diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionManager.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionManager.java index a92e1071..e3d9ab83 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionManager.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionManager.java @@ -1,5 +1,8 @@ package me.chanjar.weixin.common.session; +/** + * @author Daniel Qian + */ public interface InternalSessionManager { /** diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSession.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSession.java index 62b60927..3c4ec20c 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSession.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSession.java @@ -1,11 +1,18 @@ package me.chanjar.weixin.common.session; -import me.chanjar.weixin.common.util.res.StringManager; - -import java.util.*; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import me.chanjar.weixin.common.util.res.StringManager; + +/** + * @author Daniel Qian + */ public class StandardSession implements WxSession, InternalSession { /** diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionFacade.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionFacade.java index e4493089..aa9f8771 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionFacade.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionFacade.java @@ -2,6 +2,9 @@ package me.chanjar.weixin.common.session; import java.util.Enumeration; +/** + * @author Daniel Qian + */ public class StandardSessionFacade implements WxSession { /** diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionManager.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionManager.java index bfc0d010..bf2e7358 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionManager.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionManager.java @@ -1,15 +1,18 @@ package me.chanjar.weixin.common.session; -import me.chanjar.weixin.common.util.res.StringManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import me.chanjar.weixin.common.util.res.StringManager; + /** - * 基于内存的session manager + * 基于内存的session manager. + * + * @author Daniel Qian */ public class StandardSessionManager implements WxSessionManager, InternalSessionManager { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/TooManyActiveSessionsException.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/TooManyActiveSessionsException.java index fa1b45fa..114dd1c4 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/TooManyActiveSessionsException.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/TooManyActiveSessionsException.java @@ -19,6 +19,8 @@ package me.chanjar.weixin.common.session; /** * An exception that indicates the maximum number of active sessions has been * reached and the server is refusing to create any new sessions. + * + * @author Daniel Qian */ public class TooManyActiveSessionsException extends IllegalStateException { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSession.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSession.java index 25bed2d2..3aa79f9a 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSession.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSession.java @@ -2,6 +2,9 @@ package me.chanjar.weixin.common.session; import java.util.Enumeration; +/** + * @author Daniel Qian + */ public interface WxSession { Object getAttribute(String name); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java index c966ddab..789e2728 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java @@ -1,5 +1,8 @@ package me.chanjar.weixin.common.session; +/** + * @author Daniel Qian + */ public interface WxSessionManager { /** diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/SignUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/SignUtils.java new file mode 100644 index 00000000..9ea33b12 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/SignUtils.java @@ -0,0 +1,40 @@ +package me.chanjar.weixin.common.util; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Hex; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +/** + *
+ *  签名工具类
+ *  Created by BinaryWang on 2018/7/11.
+ * 
+ * + * @author Binary Wang + */ +@Slf4j +public class SignUtils { + /** + * HmacSHA256 签名算法 + * + * @param message 签名数据 + * @param key 签名密钥 + */ + public static String createHmacSha256Sign(String message, String key) { + try { + Mac sha256 = Mac.getInstance("HmacSHA256"); + SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "HmacSHA256"); + sha256.init(secretKeySpec); + byte[] bytes = sha256.doFinal(message.getBytes()); + return Hex.encodeHexString(bytes).toUpperCase(); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + SignUtils.log.error(e.getMessage(), e); + } + + return null; + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/ToStringUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/ToStringUtils.java deleted file mode 100644 index a0b069d1..00000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/ToStringUtils.java +++ /dev/null @@ -1,64 +0,0 @@ -package me.chanjar.weixin.common.util; - -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -/** - *
- * 自定义的ToString方法,用于产生去掉空值属性的字符串
- * Created by Binary Wang on 2016-10-27.
- * 
- * - * @author Binary Wang - */ -public class ToStringUtils { - public static final ToStringStyle THE_STYLE = new SimpleMultiLineToStringStyle(); - - /** - * 用于产生去掉空值属性并以换行符分割各属性键值的toString字符串 - * - * @param obj - */ - public static String toSimpleString(Object obj) { - String toStringResult = ToStringBuilder.reflectionToString(obj, THE_STYLE); - String[] split = toStringResult.split(SimpleMultiLineToStringStyle.LINE_SEPARATOR); - StringBuilder result = new StringBuilder(); - for (String string : split) { - if (string.endsWith(SimpleMultiLineToStringStyle.NULL_TEXT)) { - continue; - } - - result.append(string + SimpleMultiLineToStringStyle.LINE_SEPARATOR); - } - - if (result.length() == 0) { - return ""; - } - - //如果没有非空的属性,就输出 - if (StringUtils.countMatches(result, SimpleMultiLineToStringStyle.LINE_SEPARATOR) == 2) { - return result.toString().split(SimpleMultiLineToStringStyle.LINE_SEPARATOR)[0] - + "]"; - } - - return result.deleteCharAt(result.length() - 1).toString(); - } - - private static class SimpleMultiLineToStringStyle extends ToStringStyle { - private static final long serialVersionUID = 4645306494220335355L; - private static final String LINE_SEPARATOR = "\n"; - private static final String NULL_TEXT = ""; - - public SimpleMultiLineToStringStyle() { - super(); - this.setContentStart("["); - this.setFieldSeparator(LINE_SEPARATOR + " "); - this.setFieldSeparatorAtStart(true); - this.setContentEnd(LINE_SEPARATOR + "]"); - this.setNullText(NULL_TEXT); - this.setUseShortClassName(true); - this.setUseIdentityHashCode(false); - } - } -} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java index b99b09fb..033add1a 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java @@ -1,6 +1,7 @@ package me.chanjar.weixin.common.util.http.apache; import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpHost; import org.apache.http.annotation.NotThreadSafe; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; @@ -236,9 +237,10 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { if (StringUtils.isNotBlank(this.httpProxyHost) && StringUtils.isNotBlank(this.httpProxyUsername)) { // 使用代理服务器 需要用户认证的代理服务器 CredentialsProvider provider = new BasicCredentialsProvider(); - provider.setCredentials(new AuthScope(this.httpProxyHost, this.httpProxyPort) - , new UsernamePasswordCredentials(this.httpProxyUsername, this.httpProxyPassword)); + provider.setCredentials(new AuthScope(this.httpProxyHost, this.httpProxyPort), + new UsernamePasswordCredentials(this.httpProxyUsername, this.httpProxyPassword)); this.httpClientBuilder.setDefaultCredentialsProvider(provider); + this.httpClientBuilder.setProxy(new HttpHost(this.httpProxyHost, this.httpProxyPort)); } if (StringUtils.isNotBlank(this.userAgent)) { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java index 19c79bdc..dfca21a7 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java @@ -1,6 +1,7 @@ package me.chanjar.weixin.common.util.http.apache; import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpHost; import org.apache.http.annotation.NotThreadSafe; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; @@ -226,29 +227,26 @@ public class DefaultApacheHttpClientBuilder implements ApacheHttpClientBuilder { .setConnectionManager(connectionManager) .setConnectionManagerShared(true) .setSSLSocketFactory(this.buildSSLConnectionSocketFactory()) - .setDefaultRequestConfig( - RequestConfig.custom() - .setSocketTimeout(this.soTimeout) - .setConnectTimeout(this.connectionTimeout) - .setConnectionRequestTimeout(this.connectionRequestTimeout) - .build() - ) - .setRetryHandler(this.httpRequestRetryHandler); - - if (StringUtils.isNotBlank(this.httpProxyHost) - && StringUtils.isNotBlank(this.httpProxyUsername)) { + .setDefaultRequestConfig(RequestConfig.custom() + .setSocketTimeout(this.soTimeout) + .setConnectTimeout(this.connectionTimeout) + .setConnectionRequestTimeout(this.connectionRequestTimeout) + .build() + ).setRetryHandler(this.httpRequestRetryHandler); + + if (StringUtils.isNotBlank(this.httpProxyHost) && StringUtils.isNotBlank(this.httpProxyUsername)) { // 使用代理服务器 需要用户认证的代理服务器 CredentialsProvider provider = new BasicCredentialsProvider(); - provider.setCredentials( - new AuthScope(this.httpProxyHost, this.httpProxyPort), - new UsernamePasswordCredentials(this.httpProxyUsername, - this.httpProxyPassword)); + provider.setCredentials(new AuthScope(this.httpProxyHost, this.httpProxyPort), + new UsernamePasswordCredentials(this.httpProxyUsername, this.httpProxyPassword)); httpClientBuilder.setDefaultCredentialsProvider(provider); + httpClientBuilder.setProxy(new HttpHost(this.httpProxyHost, this.httpProxyPort)); } if (StringUtils.isNotBlank(this.userAgent)) { httpClientBuilder.setUserAgent(this.userAgent); } + this.closeableHttpClient = httpClientBuilder.build(); prepared.set(true); } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMediaUploadResultAdapter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMediaUploadResultAdapter.java index f33e90d5..3cb32c5e 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMediaUploadResultAdapter.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMediaUploadResultAdapter.java @@ -1,10 +1,14 @@ package me.chanjar.weixin.common.util.json; -import com.google.gson.*; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; - import java.lang.reflect.Type; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; + /** * @author Daniel Qian */ @@ -12,22 +16,25 @@ public class WxMediaUploadResultAdapter implements JsonDeserializer com.github.binarywang weixin-java-parent - 3.1.0 + 3.2.0 weixin-java-cp diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/WxCpConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/WxCpConsts.java new file mode 100644 index 00000000..4eb52a90 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/WxCpConsts.java @@ -0,0 +1,129 @@ +package me.chanjar.weixin.cp; + +/** + *
+ * 企业微信常量
+ * Created by Binary Wang on 2018/8/25.
+ * 
+ * + * @author Binary Wang + */ +public class WxCpConsts { + /** + * 企业微信端推送过来的事件类型. + * 参考文档:https://work.weixin.qq.com/api/doc#12974 + */ + public static class EventType { + /** + * 成员关注事件. + */ + public static final String SUBSCRIBE = "subscribe"; + + /** + * 成员取消关注事件. + */ + public static final String UNSUBSCRIBE = "unsubscribe"; + + /** + * 进入应用事件. + */ + public static final String ENTER_AGENT = "enter_agent"; + + /** + * 上报地理位置. + */ + public static final String LOCATION = "LOCATION"; + + /** + * 异步任务完成事件推送. + */ + public static final String BATCH_JOB_RESULT = "batch_job_result"; + + /** + * 企业微信通讯录变更事件. + */ + public static final String CHANGE_CONTACT = "change_contact"; + + /** + * 点击菜单拉取消息的事件推送. + */ + public static final String CLICK = "click"; + + /** + * 点击菜单跳转链接的事件推送. + */ + public static final String VIEW = "view"; + + /** + * 扫码推事件的事件推送. + */ + public static final String SCANCODE_PUSH = "scancode_push"; + + /** + * 扫码推事件且弹出“消息接收中”提示框的事件推送. + */ + public static final String SCANCODE_WAITMSG = "scancode_waitmsg"; + + /** + * 弹出系统拍照发图的事件推送. + */ + public static final String PIC_SYSPHOTO = "pic_sysphoto"; + + /** + * 弹出拍照或者相册发图的事件推送. + */ + public static final String PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; + + /** + * 弹出微信相册发图器的事件推送. + */ + public static final String PIC_WEIXIN = "pic_weixin"; + + /** + * 弹出地理位置选择器的事件推送. + */ + public static final String LOCATION_SELECT = "location_select"; + + } + + /** + * 企业微信通讯录变更事件. + */ + public static class ContactChangeType { + /** + * 新增成员事件. + */ + public static final String CREATE_USER = "create_user"; + + /** + * 更新成员事件. + */ + public static final String UPDATE_USER = "update_user"; + + /** + * 删除成员事件. + */ + public static final String DELETE_USER = "delete_user"; + + /** + * 新增部门事件. + */ + public static final String CREATE_PARTY = "create_party"; + + /** + * 更新部门事件. + */ + public static final String UPDATE_PARTY = "update_party"; + + /** + * 删除部门事件. + */ + public static final String DELETE_PARTY = "delete_party"; + + /** + * 标签成员变更事件. + */ + public static final String UPDATE_TAG = "update_tag"; + + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpAgentService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpAgentService.java index 3fbc981b..feea8acb 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpAgentService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpAgentService.java @@ -3,9 +3,12 @@ package me.chanjar.weixin.cp.api; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.bean.WxCpAgent; +import java.util.List; + /** *
  *  管理企业号应用
+ *  文档地址:https://work.weixin.qq.com/api/doc#10087
  *  Created by huansinho on 2018/4/13.
  * 
* @@ -17,7 +20,7 @@ public interface WxCpAgentService { *
    * 获取企业号应用信息
    * 该API用于获取企业号某个应用的基本信息,包括头像、昵称、帐号类型、认证类型、可见范围等信息
-   * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=获取企业号应用
+   * 详情请见: https://work.weixin.qq.com/api/doc#10087
    * 
* * @param agentId 企业应用的id @@ -25,4 +28,25 @@ public interface WxCpAgentService { */ WxCpAgent get(Integer agentId) throws WxErrorException; + /** + *
+   * 设置应用.
+   * 仅企业可调用,可设置当前凭证对应的应用;第三方不可调用。
+   * 详情请见: https://work.weixin.qq.com/api/doc#10088
+   * 
+ * + * @param agentInfo 应用信息 + */ + void set(WxCpAgent agentInfo) throws WxErrorException; + + /** + *
+   * 获取应用列表.
+   * 企业仅可获取当前凭证对应的应用;第三方仅可获取被授权的应用。
+   * 详情请见: https://work.weixin.qq.com/api/doc#11214
+   * 
+ * + */ + List list() throws WxErrorException; + } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java index bef0401e..19e6de44 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java @@ -9,17 +9,20 @@ import me.chanjar.weixin.common.error.WxErrorException; /** *
- *  媒体管理接口
+ *  媒体管理接口.
  *  Created by BinaryWang on 2017/6/24.
  * 
* * @author Binary Wang */ public interface WxCpMediaService { + String MEDIA_GET_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; + String MEDIA_UPLOAD_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type="; + String IMG_UPLOAD_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg"; /** *
-   * 上传多媒体文件
+   * 上传多媒体文件.
    * 上传的多媒体文件有格式和大小限制,如下:
    *   图片(image): 1M,支持JPG格式
    *   语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式
@@ -36,6 +39,8 @@ public interface WxCpMediaService {
     throws WxErrorException, IOException;
 
   /**
+   * 上传多媒体文件.
+   *
    * @param mediaType 媒体类型
    * @param file      文件对象
    * @see #upload(String, String, InputStream)
@@ -44,7 +49,7 @@ public interface WxCpMediaService {
 
   /**
    * 
-   * 下载多媒体文件
+   * 下载多媒体文件.
    * 根据微信文档,视频文件下载不了,会返回null
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
    * 
@@ -54,4 +59,17 @@ public interface WxCpMediaService { */ File download(String mediaId) throws WxErrorException; + /** + *
+   * 上传图片.
+   * 上传图片得到图片URL,该URL永久有效
+   * 返回的图片URL,仅能用于图文消息(mpnews)正文中的图片展示;若用于非企业微信域名下的页面,图片将被屏蔽。
+   * 每个企业每天最多可上传100张图片
+   * 接口url格式:https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN
+   * 
+ * + * @param file 上传的文件对象 + * @return 返回图片url + */ + String uploadImg(File file) throws WxErrorException; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java index a9fa5f94..5f3d6daa 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java @@ -34,6 +34,19 @@ public interface WxCpOAuth2Service { */ String buildAuthorizationUrl(String redirectUri, String state); + /** + *
+   * 构造oauth2授权的url连接
+   * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=企业获取code
+   * 
+ * + * @param redirectUri 跳转链接地址 + * @param state 状态码 + * @param scope 取值参考me.chanjar.weixin.common.api.WxConsts.OAuth2Scope类 + * @return url + */ + String buildAuthorizationUrl(String redirectUri, String state, String scope); + /** *
    * 用oauth2获取用户信息
@@ -51,16 +64,17 @@ public interface WxCpOAuth2Service {
 
   /**
    * 
-   * 用oauth2获取用户信息
+   * 根据code获取成员信息
    * http://qydev.weixin.qq.com/wiki/index.php?title=根据code获取成员信息
+   * https://work.weixin.qq.com/api/doc#10028/根据code获取成员信息
    * 因为企业号oauth2.0必须在应用设置里设置通过ICP备案的可信域名,所以无法测试,因此这个方法很可能是坏的。
    *
    * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
    * 
* * @param agentId 企业号应用的id - * @param code 微信oauth授权返回的代码 - * @return [userid, deviceid] + * @param code 通过成员授权获取到的code,最大为512字节。每次成员授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。 + * @return [UserId, DeviceId, OpenId, user_ticket, expires_in] * @see #getUserInfo(String) */ String[] getUserInfo(Integer agentId, String code) throws WxErrorException; @@ -77,7 +91,7 @@ public interface WxCpOAuth2Service { * 需要有对应应用的使用权限,且成员必须在授权应用的可见范围内。 *
* - * @param userTicket 成员票据 + * @param userTicket 成员票据 */ WxCpUserDetail getUserDetail(String userTicket) throws WxErrorException; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java index 05211d71..9f931725 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java @@ -1,11 +1,12 @@ package me.chanjar.weixin.cp.api; +import java.util.List; +import java.util.Map; + import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.bean.WxCpInviteResult; import me.chanjar.weixin.cp.bean.WxCpUser; - -import java.util.List; -import java.util.Map; +import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo; /** *
@@ -18,7 +19,7 @@ import java.util.Map;
 public interface WxCpUserService {
   /**
    * 
-   *   用在二次验证的时候
+   *   用在二次验证的时候.
    *   企业在员工验证成功后,调用本方法告诉企业号平台该员工关注成功。
    * 
* @@ -28,7 +29,7 @@ public interface WxCpUserService { /** *
-   * 获取部门成员(详情)
+   * 获取部门成员(详情).
    *
    * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98.28.E8.AF.A6.E6.83.85.29
    * 
@@ -41,7 +42,7 @@ public interface WxCpUserService { /** *
-   * 获取部门成员
+   * 获取部门成员.
    *
    * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98
    * 
@@ -53,14 +54,14 @@ public interface WxCpUserService { List listSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; /** - * 新建用户 + * 新建用户. * * @param user 用户对象 */ void create(WxCpUser user) throws WxErrorException; /** - * 更新用户 + * 更新用户. * * @param user 用户对象 */ @@ -68,7 +69,7 @@ public interface WxCpUserService { /** *
-   * 删除用户/批量删除成员
+   * 删除用户/批量删除成员.
    * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E6.89.B9.E9.87.8F.E5.88.A0.E9.99.A4.E6.88.90.E5.91.98
    * 
* @@ -77,7 +78,7 @@ public interface WxCpUserService { void delete(String... userIds) throws WxErrorException; /** - * 获取用户 + * 获取用户. * * @param userid 用户id */ @@ -85,7 +86,7 @@ public interface WxCpUserService { /** *
-   * 邀请成员
+   * 邀请成员.
    * 企业可通过接口批量邀请成员使用企业微信,邀请后将通过短信或邮件下发通知。
    * 请求方式:POST(HTTPS)
    * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/batch/invite?access_token=ACCESS_TOKEN
@@ -113,14 +114,14 @@ public interface WxCpUserService {
    * @param userId  企业内的成员id
    * @param agentId 非必填,整型,仅用于发红包。其它场景该参数不要填,如微信支付、企业转账、电子发票
    * @return map对象,可能包含以下值:
-   * - openid	企业微信成员userid对应的openid,若有传参agentid,则是针对该agentid的openid。否则是针对企业微信corpid的openid
-   * - appid	应用的appid,若请求包中不包含agentid则不返回appid。该appid在使用微信红包时会用到
+   * - openid 企业微信成员userid对应的openid,若有传参agentid,则是针对该agentid的openid。否则是针对企业微信corpid的openid
+   * - appid 应用的appid,若请求包中不包含agentid则不返回appid。该appid在使用微信红包时会用到
    */
   Map userId2Openid(String userId, Integer agentId) throws WxErrorException;
 
   /**
    * 
-   * openid转userid
+   * openid转userid.
    *
    * 该接口主要应用于使用微信支付、微信红包和企业转账之后的结果查询。
    * 开发者需要知道某个结果事件的openid对应企业微信内成员的信息时,可以通过调用该接口进行转换查询。
@@ -134,4 +135,17 @@ public interface WxCpUserService {
    * @return userid 该openid在企业微信对应的成员userid
    */
   String openid2UserId(String openid) throws WxErrorException;
+
+  /**
+   * 获取外部联系人详情.
+   * 
+   *   企业可通过此接口,根据外部联系人的userid,拉取外部联系人详情。权限说明:
+   * 企业需要使用外部联系人管理secret所获取的accesstoken来调用
+   * 第三方应用需拥有“企业客户”权限。
+   * 第三方应用调用时,返回的跟进人follow_user仅包含应用可见范围之内的成员。
+   * 
+ * + * @param userId 外部联系人的userid + */ + WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java index 3a2733b8..e4914134 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java @@ -1,9 +1,17 @@ package me.chanjar.weixin.cp.api.impl; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; +import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.api.WxCpAgentService; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpAgent; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.util.List; /** @@ -15,6 +23,8 @@ import me.chanjar.weixin.cp.bean.WxCpAgent; * @author huansinho */ public class WxCpAgentServiceImpl implements WxCpAgentService { + private static final JsonParser JSON_PARSER = new JsonParser(); + private WxCpService mainService; public WxCpAgentServiceImpl(WxCpService mainService) { @@ -23,15 +33,36 @@ public class WxCpAgentServiceImpl implements WxCpAgentService { @Override public WxCpAgent get(Integer agentId) throws WxErrorException { - - String url = "https://qyapi.weixin.qq.com/cgi-bin/agent/get"; - if (agentId != null) { - url += "?agentid=" + agentId; - } else { + if (agentId == null) { throw new IllegalArgumentException("缺少agentid参数"); } + + String url = "https://qyapi.weixin.qq.com/cgi-bin/agent/get?agentid=" + agentId; String responseContent = this.mainService.get(url, null); return WxCpAgent.fromJson(responseContent); } + @Override + public void set(WxCpAgent agentInfo) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/agent/set"; + String responseContent = this.mainService.post(url, agentInfo.toJson()); + JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); + if (jsonObject.get("errcode").getAsInt() != 0) { + throw new WxErrorException(WxError.fromJson(responseContent)); + } + } + + @Override + public List list() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/agent/list"; + String responseContent = this.mainService.get(url, null); + JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); + if (jsonObject.get("errcode").getAsInt() != 0) { + throw new WxErrorException(WxError.fromJson(responseContent)); + } + + return WxCpGsonBuilder.create().fromJson(jsonObject.get("agentlist").toString(), new TypeToken>() { + }.getType()); + } + } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java index f1cf272f..c3dc4774 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java @@ -1,5 +1,10 @@ package me.chanjar.weixin.cp.api.impl; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; + import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; @@ -8,17 +13,13 @@ import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.cp.api.WxCpMediaService; import me.chanjar.weixin.cp.api.WxCpService; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.UUID; - /** *
- * 媒体管理接口
+ * 媒体管理接口.
  * Created by Binary Wang on 2017-6-25.
- * @author Binary Wang
  * 
+ * + * @author Binary Wang */ public class WxCpMediaServiceImpl implements WxCpMediaService { private WxCpService mainService; @@ -35,16 +36,22 @@ public class WxCpMediaServiceImpl implements WxCpMediaService { @Override public WxMediaUploadResult upload(String mediaType, File file) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; - return this.mainService.execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), url, file); + return this.mainService.execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), + MEDIA_UPLOAD_URL + mediaType, file); } @Override public File download(String mediaId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; return this.mainService.execute( BaseMediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(), this.mainService.getWxCpConfigStorage().getTmpDirFile()), - url, "media_id=" + mediaId); + MEDIA_GET_URL, "media_id=" + mediaId); + } + + @Override + public String uploadImg(File file) throws WxErrorException { + final WxMediaUploadResult result = this.mainService + .execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), IMG_UPLOAD_URL, file); + return result.getUrl(); } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java index f5950f5b..8f0375f3 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java @@ -4,6 +4,7 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.URIUtil; import me.chanjar.weixin.common.util.json.GsonHelper; @@ -16,6 +17,8 @@ import me.chanjar.weixin.cp.bean.WxCpUserDetail; * * Created by Binary Wang on 2017-6-25. * @author Binary Wang + * + * @author Binary Wang *
*/ public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service { @@ -35,16 +38,27 @@ public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service { @Override public String buildAuthorizationUrl(String redirectUri, String state) { - String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"; - url += "appid=" + this.mainService.getWxCpConfigStorage().getCorpId(); - url += "&redirect_uri=" + URIUtil.encodeURIComponent(redirectUri); - url += "&response_type=code"; - url += "&scope=snsapi_base"; + return this.buildAuthorizationUrl(redirectUri, state, WxConsts.OAuth2Scope.SNSAPI_BASE); + } + + @Override + public String buildAuthorizationUrl(String redirectUri, String state, String scope) { + StringBuilder url = new StringBuilder("https://open.weixin.qq.com/connect/oauth2/authorize?"); + url.append("appid=").append(this.mainService.getWxCpConfigStorage().getCorpId()); + url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectUri)); + url.append("&response_type=code"); + url.append("&scope=").append(scope); + + if (WxConsts.OAuth2Scope.SNSAPI_PRIVATEINFO.equals(scope) + || WxConsts.OAuth2Scope.SNSAPI_USERINFO.equals(scope)) { + url.append("&agentid=").append(this.mainService.getWxCpConfigStorage().getAgentId()); + } + if (state != null) { - url += "&state=" + state; + url.append("&state=").append(state); } - url += "#wechat_redirect"; - return url; + url.append("#wechat_redirect"); + return url.toString(); } @Override @@ -61,7 +75,10 @@ public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service { JsonObject jo = je.getAsJsonObject(); return new String[]{GsonHelper.getString(jo, "UserId"), GsonHelper.getString(jo, "DeviceId"), - GsonHelper.getString(jo, "OpenId")}; + GsonHelper.getString(jo, "OpenId"), + GsonHelper.getString(jo, "user_ticket"), + GsonHelper.getString(jo, "expires_in") + }; } @Override diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java index e4baff52..68224b1e 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java @@ -1,18 +1,23 @@ package me.chanjar.weixin.cp.api.impl; +import java.util.List; +import java.util.Map; + import com.google.common.collect.Maps; -import com.google.gson.*; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonPrimitive; import com.google.gson.reflect.TypeToken; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.api.WxCpUserService; import me.chanjar.weixin.cp.bean.WxCpInviteResult; import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; -import java.util.List; -import java.util.Map; - /** *
  *  Created by BinaryWang on 2017/6/24.
@@ -178,4 +183,11 @@ public class WxCpUserServiceImpl implements WxCpUserService {
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return tmpJsonElement.getAsJsonObject().get("userid").getAsString();
   }
+
+  @Override
+  public WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException {
+    String url = "https://qyapi.weixin.qq.com/cgi-bin/crm/get_external_contact?external_userid=" + userId;
+    String responseContent = this.mainService.get(url, null);
+    return WxCpUserExternalContactInfo.fromJson(responseContent);
+  }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgent.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgent.java
index eb7069bd..b70571f0 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgent.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgent.java
@@ -1,7 +1,10 @@
 package me.chanjar.weixin.cp.bean;
 
 import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
 import java.io.Serializable;
@@ -16,16 +19,20 @@ import java.util.List;
  * @author huansinho
  */
 @Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
 public class WxCpAgent implements Serializable {
+  private static final long serialVersionUID = 5002894979081127234L;
 
   @SerializedName("errcode")
-  private Integer errcode;
+  private Integer errCode;
 
   @SerializedName("errmsg")
-  private String errmsg;
+  private String errMsg;
 
   @SerializedName("agentid")
-  private Integer agentid;
+  private Integer agentId;
 
   @SerializedName("name")
   private String name;
@@ -33,14 +40,17 @@ public class WxCpAgent implements Serializable {
   @SerializedName("square_logo_url")
   private String squareLogoUrl;
 
+  @SerializedName("logo_mediaid")
+  private String logoMediaId;
+
   @SerializedName("description")
   private String description;
 
   @SerializedName("allow_userinfos")
-  private Users allowUserinfos;
+  private Users allowUserInfos;
 
   @SerializedName("allow_partys")
-  private Partys allowPartys;
+  private Parties allowParties;
 
   @SerializedName("allow_tags")
   private Tags allowTags;
@@ -55,7 +65,7 @@ public class WxCpAgent implements Serializable {
   private Integer reportLocationFlag;
 
   @SerializedName("isreportenter")
-  private Integer isreportenter;
+  private Integer isReportEnter;
 
   @SerializedName("home_url")
   private String homeUrl;
@@ -71,26 +81,25 @@ public class WxCpAgent implements Serializable {
   @Data
   public static class Users implements Serializable {
     @SerializedName("user")
-    private List user;
+    private List users;
   }
 
-
   @Data
   public class User implements Serializable {
     @SerializedName("userid")
-    private String userid;
+    private String userId;
   }
 
   @Data
-  public class Partys {
+  public class Parties {
     @SerializedName("partyid")
-    private List partyids = null;
+    private List partyIds = null;
   }
 
   @Data
   public class Tags {
     @SerializedName("tagid")
-    private List tagids = null;
+    private List tagIds = null;
   }
 
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpInviteResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpInviteResult.java
index 35f61ba0..f6ff4634 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpInviteResult.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpInviteResult.java
@@ -1,15 +1,17 @@
 package me.chanjar.weixin.cp.bean;
 
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.common.base.Splitter;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.List;
 
 /**
  * 邀请成员的结果对象类.
@@ -23,7 +25,7 @@ public class WxCpInviteResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   public static WxCpInviteResult fromJson(String json) {
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessageSendResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessageSendResult.java
index e54a01ec..9d0a85b6 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessageSendResult.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessageSendResult.java
@@ -1,15 +1,17 @@
 package me.chanjar.weixin.cp.bean;
 
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.common.base.Splitter;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.List;
 
 /**
  * 消息发送结果对象类.
@@ -23,7 +25,7 @@ public class WxCpMessageSendResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   public static WxCpMessageSendResult fromJson(String json) {
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagAddOrRemoveUsersResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagAddOrRemoveUsersResult.java
index 3d89c073..67d90978 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagAddOrRemoveUsersResult.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagAddOrRemoveUsersResult.java
@@ -1,15 +1,17 @@
 package me.chanjar.weixin.cp.bean;
 
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.common.base.Splitter;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.List;
 
 /**
  * 为标签添加或移除用户结果对象类.
@@ -23,7 +25,7 @@ public class WxCpTagAddOrRemoveUsersResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   public static WxCpTagAddOrRemoveUsersResult fromJson(String json) {
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java
index fd06ea23..f3d5aa22 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java
@@ -1,13 +1,15 @@
 package me.chanjar.weixin.cp.bean;
 
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
-
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
 /**
  * 微信用户信息.
  *
@@ -24,6 +26,7 @@ public class WxCpUser implements Serializable {
   private Gender gender;
   private String email;
   private String avatar;
+  private String avatarMediaId;
   private Integer status;
   private Integer enable;
   private Integer isLeader;
@@ -33,6 +36,14 @@ public class WxCpUser implements Serializable {
   private String telephone;
   private String qrCode;
   private Boolean toInvite;
+  /**
+   * 成员对外信息.
+   */
+  private List externalAttrs = new ArrayList<>();
+
+  public void addExternalAttr(ExternalAttribute externalAttr) {
+    this.externalAttrs.add(externalAttr);
+  }
 
   public void addExtAttr(String name, String value) {
     this.extAttrs.add(new Attr(name, value));
@@ -53,4 +64,39 @@ public class WxCpUser implements Serializable {
     private String value;
   }
 
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class ExternalAttribute {
+    /**
+     * 属性类型: 0-本文 1-网页 2-小程序.
+     */
+    private int type;
+    /**
+     * 属性名称: 需要先确保在管理端有创建改属性,否则会忽略.
+     */
+    private String name;
+    /**
+     * 文本属性内容,长度限制12个UTF8字符.
+     */
+    private String value;
+    /**
+     * 网页的url,必须包含http或者https头.
+     */
+    private String url;
+    /**
+     * 小程序的展示标题,长度限制12个UTF8字符.
+     * 或者 网页的展示标题,长度限制12个UTF8字符
+     */
+    private String title;
+    /**
+     * 小程序appid,必须是有在本企业安装授权的小程序,否则会被忽略.
+     */
+    private String appid;
+    /**
+     * 小程序的页面路径.
+     */
+    private String pagePath;
+  }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserDetail.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserDetail.java
index d8df026d..1d40e94a 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserDetail.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserDetail.java
@@ -13,12 +13,42 @@ import lombok.Data;
  */
 @Data
 public class WxCpUserDetail {
+
+  /**
+   * 成员UserID
+   */
   @SerializedName("userid")
   private String userId;
+
+  /**
+   * 成员姓名
+   */
   private String name;
+
+  /**
+   * 成员手机号,仅在用户同意snsapi_privateinfo授权时返回
+   */
   private String mobile;
+
+  /**
+   * 性别。0表示未定义,1表示男性,2表示女性
+   */
   private String gender;
+
+  /**
+   * 成员邮箱,仅在用户同意snsapi_privateinfo授权时返回
+   */
   private String email;
-  @SerializedName("qrCode")
+
+  /**
+   * 头像url。注:如果要获取小图将url最后的”/0”改成”/100”即可。仅在用户同意snsapi_privateinfo授权时返回
+   */
+  private String avatar;
+
+  /**
+   * 员工个人二维码(扫描可添加为外部联系人),仅在用户同意snsapi_privateinfo授权时返回
+   */
+  @SerializedName("qr_code")
   private String qrCode;
+
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactInfo.java
new file mode 100644
index 00000000..466eac4a
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactInfo.java
@@ -0,0 +1,126 @@
+package me.chanjar.weixin.cp.bean;
+
+import java.util.List;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * 
+ * 外部联系人详情
+ * Created by Binary Wang on 2018/9/16.
+ * 参考文档:https://work.weixin.qq.com/api/doc#13878
+ * 
+ * + * @author Binary Wang + */ +@Getter +@Setter +public class WxCpUserExternalContactInfo { + @SerializedName("external_contact") + private ExternalContact externalContact; + + @SerializedName("follow_user") + private List followedUsers; + + @Getter + @Setter + public static class ExternalContact { + @SerializedName("external_userid") + private String externalUserId; + + @SerializedName("position") + private String position; + + @SerializedName("name") + private String name; + + @SerializedName("avatar") + private String avatar; + + @SerializedName("corp_name") + private String corpName; + + @SerializedName("corp_full_name") + private String corpFullName; + + @SerializedName("type") + private Integer type; + + @SerializedName("gender") + private Integer gender; + + @SerializedName("unionid") + private String unionId; + + @SerializedName("external_profile") + private ExternalProfile externalProfile; + } + + @Setter + @Getter + public static class ExternalProfile { + @SerializedName("external_attr") + private List externalAttrs; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class ExternalAttribute { + @Setter + @Getter + public static class Text { + private String value; + } + + @Setter + @Getter + public static class Web { + private String title; + private String url; + } + + @Setter + @Getter + public static class MiniProgram { + @SerializedName("pagepath") + private String pagePath; + private String appid; + private String title; + } + + private int type; + + private String name; + + private Text text; + + private Web web; + + @SerializedName("miniprogram") + private MiniProgram miniProgram; + } + + @Setter + @Getter + public static class FollowedUser { + @SerializedName("userid") + private String userId; + private String remark; + private String description; + @SerializedName("createtime") + private Long createTime; + } + + public static WxCpUserExternalContactInfo fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpUserExternalContactInfo.class); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java index 785884a1..abb880d2 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java @@ -1,35 +1,38 @@ package me.chanjar.weixin.cp.bean; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamConverter; import lombok.Data; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.api.WxConsts; -import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; import me.chanjar.weixin.cp.config.WxCpConfigStorage; import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; import me.chanjar.weixin.cp.util.xml.XStreamTransformer; -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; /** *
  * 微信推送过来的消息,也是同步回复给用户的消息,xml格式
  * 相关字段的解释看微信开发者文档:
- * http://mp.weixin.qq.com/wiki/index.php?title=接收普通消息
- * http://mp.weixin.qq.com/wiki/index.php?title=接收事件推送
- * http://mp.weixin.qq.com/wiki/index.php?title=接收语音识别结果
+ * https://work.weixin.qq.com/api/doc#12973
+ * https://work.weixin.qq.com/api/doc#12974
  * 
* * @author Daniel Qian */ -@XStreamAlias("xml") @Data +@Slf4j +@XStreamAlias("xml") public class WxCpXmlMessage implements Serializable { private static final long serialVersionUID = -1042994982179476410L; @@ -51,6 +54,24 @@ public class WxCpXmlMessage implements Serializable { @XStreamAlias("CreateTime") private Long createTime; + /** + *
+   * 当接受用户消息时,可能会获得以下值:
+   * {@link WxConsts.XmlMsgType#TEXT}
+   * {@link WxConsts.XmlMsgType#IMAGE}
+   * {@link WxConsts.XmlMsgType#VOICE}
+   * {@link WxConsts.XmlMsgType#VIDEO}
+   * {@link WxConsts.XmlMsgType#LOCATION}
+   * {@link WxConsts.XmlMsgType#LINK}
+   * {@link WxConsts.XmlMsgType#EVENT}
+   * 当发送消息的时候使用:
+   * {@link WxConsts.XmlMsgType#TEXT}
+   * {@link WxConsts.XmlMsgType#IMAGE}
+   * {@link WxConsts.XmlMsgType#VOICE}
+   * {@link WxConsts.XmlMsgType#VIDEO}
+   * {@link WxConsts.XmlMsgType#NEWS}
+   * 
+ */ @XStreamAlias("MsgType") @XStreamConverter(value = XStreamCDataConverter.class) private String msgType; @@ -128,15 +149,172 @@ public class WxCpXmlMessage implements Serializable { @XStreamConverter(value = XStreamCDataConverter.class) private String recognition; + /** + * 通讯录变更事件. + * 请参考常量 me.chanjar.weixin.cp.WxCpConsts.ContactChangeType + */ + @XStreamAlias("ChangeType") + @XStreamConverter(value = XStreamCDataConverter.class) + private String changeType; + + /** + * 变更信息的成员UserID. + */ + @XStreamAlias("UserID") + @XStreamConverter(value = XStreamCDataConverter.class) + private String userId; + + /** + * 新的UserID,变更时推送(userid由系统生成时可更改一次). + */ + @XStreamAlias("NewUserID") + @XStreamConverter(value = XStreamCDataConverter.class) + private String newUserId; + + /** + * 成员名称. + * 或者部门名称 + */ + @XStreamAlias("Name") + @XStreamConverter(value = XStreamCDataConverter.class) + private String name; + + /** + * 成员部门列表. + */ + @XStreamAlias("Department") + @XStreamConverter(value = XStreamCDataConverter.class) + private String department; + + /** + * 手机号码. + */ + @XStreamAlias("Mobile") + @XStreamConverter(value = XStreamCDataConverter.class) + private String mobile; + + /** + * 职位信息。长度为0~64个字节. + */ + @XStreamAlias("Position") + @XStreamConverter(value = XStreamCDataConverter.class) + private String position; + + /** + * 性别,1表示男性,2表示女性. + */ + @XStreamAlias("Gender") + private Integer gender; + + /** + * 邮箱. + */ + @XStreamAlias("Email") + @XStreamConverter(value = XStreamCDataConverter.class) + private String email; + + /** + * 头像url。注:如果要获取小图将url最后的”/0”改成”/100”即可. + */ + @XStreamAlias("Avatar") + @XStreamConverter(value = XStreamCDataConverter.class) + private String avatar; + + /** + * 英文名. + */ + @XStreamAlias("EnglishName") + @XStreamConverter(value = XStreamCDataConverter.class) + private String englishName; + + /** + * 上级字段,标识是否为上级。0表示普通成员,1表示上级. + */ + @XStreamAlias("IsLeader") + private Integer isLeader; + + /** + * 座机. + */ + @XStreamAlias("Telephone") + @XStreamConverter(value = XStreamCDataConverter.class) + private String telephone; + + /** + * 扩展属性. + */ + @XStreamAlias("ExtAttr") + private ExtAttr extAttrs = new ExtAttr(); + + /** + * 部门Id. + */ + @XStreamAlias("Id") + private Integer id; + + /** + * 父部门id. + */ + @XStreamAlias("ParentId") + @XStreamConverter(value = XStreamCDataConverter.class) + private String parentId; + + /** + * 部门排序. + */ + @XStreamAlias("Order") + @XStreamConverter(value = XStreamCDataConverter.class) + private String order; + + /** + * 标签Id. + */ + @XStreamAlias("TagId") + @XStreamConverter(value = XStreamCDataConverter.class) + private String tagId; + + /** + * 标签中新增的成员userid列表,用逗号分隔. + */ + @XStreamAlias("AddUserItems") + @XStreamConverter(value = XStreamCDataConverter.class) + private String addUserItems; + + /** + * 标签中删除的成员userid列表,用逗号分隔. + */ + @XStreamAlias("DelUserItems") + @XStreamConverter(value = XStreamCDataConverter.class) + private String delUserItems; + + /** + * 标签中新增的部门id列表,用逗号分隔. + */ + @XStreamAlias("AddPartyItems") + @XStreamConverter(value = XStreamCDataConverter.class) + private String addPartyItems; + + /** + * 标签中删除的部门id列表,用逗号分隔. + */ + @XStreamAlias("DelPartyItems") + @XStreamConverter(value = XStreamCDataConverter.class) + private String delPartyItems; + + /////////////////////////////////////// // 群发消息返回的结果 /////////////////////////////////////// /** - * 群发的结果. + * 多个时间共用字段. + * 1. 群发的结果. + * 2. 通讯录变更事件 + * 激活状态:1=已激活 2=已禁用 4=未激活 已激活代表已激活企业微信或已关注微工作台(原企业号). */ @XStreamAlias("Status") @XStreamConverter(value = XStreamCDataConverter.class) private String status; + /** * group_id下粉丝数;或者openid_list中的粉丝数. */ @@ -181,19 +359,16 @@ public class WxCpXmlMessage implements Serializable { /** * 从加密字符串转换. */ - public static WxCpXmlMessage fromEncryptedXml( - String encryptedXml, - WxCpConfigStorage wxCpConfigStorage, - String timestamp, String nonce, String msgSignature) { + public static WxCpXmlMessage fromEncryptedXml(String encryptedXml, WxCpConfigStorage wxCpConfigStorage, + String timestamp, String nonce, String msgSignature) { WxCpCryptUtil cryptUtil = new WxCpCryptUtil(wxCpConfigStorage); String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml); + log.debug("解密后的原始xml消息内容:{}", plainText); return fromXml(plainText); } - public static WxCpXmlMessage fromEncryptedXml( - InputStream is, - WxCpConfigStorage wxCpConfigStorage, - String timestamp, String nonce, String msgSignature) { + public static WxCpXmlMessage fromEncryptedXml(InputStream is, WxCpConfigStorage wxCpConfigStorage, + String timestamp, String nonce, String msgSignature) { try { return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxCpConfigStorage, timestamp, nonce, msgSignature); } catch (IOException e) { @@ -201,39 +376,9 @@ public class WxCpXmlMessage implements Serializable { } } - /** - *
-   * 当接受用户消息时,可能会获得以下值:
-   * {@link WxConsts.XmlMsgType#TEXT}
-   * {@link WxConsts.XmlMsgType#IMAGE}
-   * {@link WxConsts.XmlMsgType#VOICE}
-   * {@link WxConsts.XmlMsgType#VIDEO}
-   * {@link WxConsts.XmlMsgType#LOCATION}
-   * {@link WxConsts.XmlMsgType#LINK}
-   * {@link WxConsts.XmlMsgType#EVENT}
-   * 
- */ - public String getMsgType() { - return this.msgType; - } - - /** - *
-   * 当发送消息的时候使用:
-   * {@link WxConsts.XmlMsgType#TEXT}
-   * {@link WxConsts.XmlMsgType#IMAGE}
-   * {@link WxConsts.XmlMsgType#VOICE}
-   * {@link WxConsts.XmlMsgType#VIDEO}
-   * {@link WxConsts.XmlMsgType#NEWS}
-   * 
- */ - public void setMsgType(String msgType) { - this.msgType = msgType; - } - @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } @Data @@ -255,6 +400,23 @@ public class WxCpXmlMessage implements Serializable { private String scanResult; } + @Data + public static class ExtAttr { + @XStreamAlias("Item") + protected final List items = new ArrayList<>(); + + @Data + public static class Item { + @XStreamAlias("Name") + @XStreamConverter(value = XStreamCDataConverter.class) + private String name; + + @XStreamAlias("Value") + @XStreamConverter(value = XStreamCDataConverter.class) + private String value; + } + } + @Data @XStreamAlias("SendPicsInfo") public static class SendPicsInfo { diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java index 34c5499f..a053a546 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java @@ -1,16 +1,26 @@ package me.chanjar.weixin.cp.bean; +import java.io.Serializable; + import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamConverter; import lombok.Data; import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; +import me.chanjar.weixin.cp.bean.outxmlbuilder.ImageBuilder; +import me.chanjar.weixin.cp.bean.outxmlbuilder.NewsBuilder; +import me.chanjar.weixin.cp.bean.outxmlbuilder.TextBuilder; +import me.chanjar.weixin.cp.bean.outxmlbuilder.VideoBuilder; +import me.chanjar.weixin.cp.bean.outxmlbuilder.VoiceBuilder; import me.chanjar.weixin.cp.config.WxCpConfigStorage; -import me.chanjar.weixin.cp.bean.outxmlbuilder.*; import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; import me.chanjar.weixin.cp.util.xml.XStreamTransformer; -import java.io.Serializable; - +/** + * 被动回复消息. + * https://work.weixin.qq.com/api/doc#12975 + * + * @author Daniel Qian + */ @XStreamAlias("xml") @Data public abstract class WxCpXmlOutMessage implements Serializable { diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java index 2ce56e7d..707188a2 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java @@ -1,11 +1,13 @@ package me.chanjar.weixin.cp.config; +import java.io.File; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; -import java.io.File; - /** * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 * @@ -201,7 +203,7 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } @Override diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java index 133fe2ef..6ae48f0e 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java @@ -43,17 +43,24 @@ public class WxCpJedisConfigStorage implements WxCpConfigStorage { private volatile File tmpDirFile; private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + public WxCpJedisConfigStorage(JedisPool jedisPool) { + this.jedisPool = jedisPool; + } + public WxCpJedisConfigStorage(String host, int port) { - this.jedisPool = new JedisPool(host, port); + jedisPool = new JedisPool(host, port); } - public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port) { - this.jedisPool = new JedisPool(poolConfig, host, port); + jedisPool = new JedisPool(poolConfig, host, port); + } + + public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port, int timeout, String password) { + jedisPool = new JedisPool(poolConfig, host, port, timeout, password); } - public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port, int timeout, final String password) { - this.jedisPool = new JedisPool(poolConfig, host, port, timeout, password); + public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port, int timeout, String password, int database) { + jedisPool = new JedisPool(poolConfig, host, port, timeout, password, database); } /** diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java index c9c55964..f4dc691e 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java @@ -10,6 +10,9 @@ import me.chanjar.weixin.cp.bean.WxCpMessage; import me.chanjar.weixin.cp.bean.WxCpTag; import me.chanjar.weixin.cp.bean.WxCpUser; +/** + * @author Daniel Qian + */ public class WxCpGsonBuilder { public static final GsonBuilder INSTANCE = new GsonBuilder(); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java index 1eec4815..1dc3f687 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java @@ -8,21 +8,30 @@ */ package me.chanjar.weixin.cp.util.json; -import com.google.gson.*; +import java.lang.reflect.Type; + +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; import me.chanjar.weixin.common.util.json.GsonHelper; import me.chanjar.weixin.cp.bean.Gender; import me.chanjar.weixin.cp.bean.WxCpUser; -import java.lang.reflect.Type; - /** * @author Daniel Qian */ public class WxCpUserGsonAdapter implements JsonDeserializer, JsonSerializer { + private static final String EXTERNAL_PROFILE = "external_profile"; + private static final String EXTERNAL_ATTR = "external_attr"; @Override - public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { + public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject o = json.getAsJsonObject(); WxCpUser user = new WxCpUser(); @@ -43,6 +52,7 @@ public class WxCpUserGsonAdapter implements JsonDeserializer, JsonSeri user.setGender(Gender.fromCode(GsonHelper.getString(o, "gender"))); user.setEmail(GsonHelper.getString(o, "email")); user.setAvatar(GsonHelper.getString(o, "avatar")); + user.setAvatarMediaId(GsonHelper.getString(o, "avatar_mediaid")); user.setStatus(GsonHelper.getInteger(o, "status")); user.setEnable(GsonHelper.getInteger(o, "enable")); user.setIsLeader(GsonHelper.getInteger(o, "isleader")); @@ -62,6 +72,53 @@ public class WxCpUserGsonAdapter implements JsonDeserializer, JsonSeri user.getExtAttrs().add(attr); } } + + if (GsonHelper.isNotNull(o.get(EXTERNAL_PROFILE))) { + JsonArray attrJsonElements = o.get(EXTERNAL_PROFILE).getAsJsonObject().get(EXTERNAL_ATTR).getAsJsonArray(); + for (JsonElement element : attrJsonElements) { + final Integer type = GsonHelper.getInteger(element.getAsJsonObject(), "type"); + final String name = GsonHelper.getString(element.getAsJsonObject(), "name"); + + switch (type) { + case 0: { + user.getExternalAttrs() + .add(WxCpUser.ExternalAttribute.builder() + .type(type) + .name(name) + .value(GsonHelper.getString(element.getAsJsonObject().get("text").getAsJsonObject(), "value")) + .build() + ); + break; + } + case 1: { + final JsonObject web = element.getAsJsonObject().get("web").getAsJsonObject(); + user.getExternalAttrs() + .add(WxCpUser.ExternalAttribute.builder() + .type(type) + .name(name) + .url(GsonHelper.getString(web, "url")) + .title(GsonHelper.getString(web, "title")) + .build() + ); + break; + } + case 2: { + final JsonObject miniprogram = element.getAsJsonObject().get("miniprogram").getAsJsonObject(); + user.getExternalAttrs() + .add(WxCpUser.ExternalAttribute.builder() + .type(type) + .name(name) + .appid(GsonHelper.getString(miniprogram, "appid")) + .pagePath(GsonHelper.getString(miniprogram, "pagepath")) + .title(GsonHelper.getString(miniprogram, "title")) + .build() + ); + break; + } + default://ignored + } + } + } return user; } @@ -96,6 +153,9 @@ public class WxCpUserGsonAdapter implements JsonDeserializer, JsonSeri if (user.getAvatar() != null) { o.addProperty("avatar", user.getAvatar()); } + if (user.getAvatarMediaId() != null) { + o.addProperty("avatar_mediaid", user.getAvatarMediaId()); + } if (user.getStatus() != null) { o.addProperty("status", user.getStatus()); } @@ -133,6 +193,45 @@ public class WxCpUserGsonAdapter implements JsonDeserializer, JsonSeri attrsJson.add("attrs", attrsJsonArray); o.add("extattr", attrsJson); } + + if (user.getExternalAttrs().size() > 0) { + JsonArray attrsJsonArray = new JsonArray(); + for (WxCpUser.ExternalAttribute attr : user.getExternalAttrs()) { + JsonObject attrJson = new JsonObject(); + attrJson.addProperty("type",attr.getType()); + attrJson.addProperty("name", attr.getName()); + switch (attr.getType()) { + case 0: { + JsonObject text = new JsonObject(); + text.addProperty("value", attr.getValue()); + attrJson.add("text", text); + break; + } + case 1: { + JsonObject web = new JsonObject(); + web.addProperty("url", attr.getUrl()); + web.addProperty("title", attr.getTitle()); + attrJson.add("web", web); + break; + } + case 2: { + JsonObject miniprogram = new JsonObject(); + miniprogram.addProperty("appid", attr.getAppid()); + miniprogram.addProperty("pagepath", attr.getPagePath()); + miniprogram.addProperty("title", attr.getTitle()); + attrJson.add("miniprogram", miniprogram); + break; + } + default://忽略 + } + attrsJsonArray.add(attrJson); + } + + JsonObject attrsJson = new JsonObject(); + attrsJson.add(EXTERNAL_ATTR, attrsJsonArray); + o.add(EXTERNAL_PROFILE, attrsJson); + } + return o; } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImplTest.java index f4b2aac0..4ce49724 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImplTest.java @@ -1,23 +1,21 @@ package me.chanjar.weixin.cp.api.impl; import com.google.inject.Inject; -import me.chanjar.weixin.common.api.WxConsts; -import me.chanjar.weixin.common.bean.menu.WxMenu; -import me.chanjar.weixin.common.bean.menu.WxMenuButton; +import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.api.ApiTestModule; import me.chanjar.weixin.cp.api.WxCpAgentService; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpAgent; -import me.chanjar.weixin.cp.config.WxCpInMemoryConfigStorage; -import org.mockito.Mock; import org.testng.Assert; -import org.testng.annotations.DataProvider; import org.testng.annotations.Guice; import org.testng.annotations.Test; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.mockito.Mockito.*; /** @@ -28,24 +26,64 @@ import static org.mockito.Mockito.*; * * @author huansinho */ +@Guice(modules = ApiTestModule.class) public class WxCpAgentServiceImplTest { - - protected WxCpService wxService = mock(WxCpService.class); + @Inject + private WxCpService wxCpService; @Test public void testGet() throws Exception { - String returnJson = "{\"errcode\": 0,\"errmsg\": \"ok\",\"agentid\": 9,\"name\": \"测试应用\",\"square_logo_url\": \"http://wx.qlogo.cn/mmhead/alksjf;lasdjf;lasjfuodiuj3rj2o34j/0\",\"description\": \"这是一个企业号应用\",\"allow_userinfos\": {\"user\": [{\"userid\": \"0009854\"}, {\"userid\": \"1723\"}, {\"userid\": \"5625\"}]},\"allow_partys\": {\"partyid\": [42762742]},\"allow_tags\": {\"tagid\": [23, 22, 35, 19, 32, 125, 133, 46, 150, 38, 183, 9, 7]},\"close\": 0,\"redirect_domain\": \"weixin.com.cn\",\"report_location_flag\": 0,\"isreportenter\": 0,\"home_url\": \"\"}"; - when(wxService.get("https://qyapi.weixin.qq.com/cgi-bin/agent/get?agentid=9", null)).thenReturn(returnJson); - when(wxService.getAgentService()).thenReturn(new WxCpAgentServiceImpl(wxService)); + final Integer agentId = this.wxCpService.getWxCpConfigStorage().getAgentId(); + WxCpAgent wxCpAgent = this.wxCpService.getAgentService().get(agentId); + + assertThat(wxCpAgent.getAgentId()).isEqualTo(agentId); + + assertThat(wxCpAgent.getAllowUserInfos().getUsers().toArray()).isNotEmpty(); + assertThat(wxCpAgent.getAllowParties().getPartyIds().toArray()).isNotEmpty(); + assertThat(wxCpAgent.getAllowTags().getTagIds().toArray()).isNotEmpty(); + } + + @Test + public void testSet() throws WxErrorException { + final Integer agentId = this.wxCpService.getWxCpConfigStorage().getAgentId(); + + this.wxCpService.getAgentService().set(WxCpAgent.builder() + .description("abcddd") + .logoMediaId("aaaaaaaaaaaaaa") + .agentId(agentId) + .build()); + } + + @Test + public void testList() throws WxErrorException { + List list = this.wxCpService.getAgentService().list(); + + assertThat(list).isNotEmpty(); + + assertThat(list.get(0).getAgentId()).isNotNull(); + assertThat(list.get(0).getName()).isNotEmpty(); + assertThat(list.get(0).getSquareLogoUrl()).isNotEmpty(); + } + + public static class MockTest { + private WxCpService wxService = mock(WxCpService.class); + + @Test + public void testGet() throws Exception { + String returnJson = "{\"errcode\": 0,\"errmsg\": \"ok\",\"agentid\": 9,\"name\": \"测试应用\",\"square_logo_url\": \"http://wx.qlogo.cn/mmhead/alksjf;lasdjf;lasjfuodiuj3rj2o34j/0\",\"description\": \"这是一个企业号应用\",\"allow_userinfos\": {\"user\": [{\"userid\": \"0009854\"}, {\"userid\": \"1723\"}, {\"userid\": \"5625\"}]},\"allow_partys\": {\"partyid\": [42762742]},\"allow_tags\": {\"tagid\": [23, 22, 35, 19, 32, 125, 133, 46, 150, 38, 183, 9, 7]},\"close\": 0,\"redirect_domain\": \"weixin.com.cn\",\"report_location_flag\": 0,\"isreportenter\": 0,\"home_url\": \"\"}"; + when(wxService.get("https://qyapi.weixin.qq.com/cgi-bin/agent/get?agentid=9", null)).thenReturn(returnJson); + when(wxService.getAgentService()).thenReturn(new WxCpAgentServiceImpl(wxService)); + + WxCpAgentService wxAgentService = this.wxService.getAgentService(); + WxCpAgent wxCpAgent = wxAgentService.get(9); - WxCpAgentService wxAgentService = this.wxService.getAgentService(); - WxCpAgent wxCpAgent = wxAgentService.get(9); + assertEquals(9, wxCpAgent.getAgentId().intValue()); - Assert.assertEquals(9, wxCpAgent.getAgentid().intValue()); + assertEquals(new Integer[]{42762742}, wxCpAgent.getAllowParties().getPartyIds().toArray()); - Assert.assertEquals(new Integer[]{42762742}, wxCpAgent.getAllowPartys().getPartyids().toArray()); + assertEquals(new Integer[]{23, 22, 35, 19, 32, 125, 133, 46, 150, 38, 183, 9, 7}, wxCpAgent.getAllowTags().getTagIds().toArray()); - Assert.assertEquals(new Integer[]{23, 22, 35, 19, 32, 125, 133, 46, 150, 38, 183, 9, 7}, wxCpAgent.getAllowTags().getTagids().toArray()); + } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java index ad925690..d7242a77 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java @@ -1,5 +1,14 @@ package me.chanjar.weixin.cp.api.impl; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import org.testng.annotations.*; + import com.google.inject.Inject; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; @@ -7,22 +16,14 @@ import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.api.ApiTestModule; import me.chanjar.weixin.cp.api.TestConstants; import me.chanjar.weixin.cp.api.WxCpService; -import org.testng.annotations.*; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; import static org.testng.Assert.*; /** - *
- *
  * Created by Binary Wang on 2017-6-25.
+ *
  * @author Binary Wang
- * 
*/ @Guice(modules = ApiTestModule.class) public class WxCpMediaServiceImplTest { @@ -35,8 +36,8 @@ public class WxCpMediaServiceImplTest { public Object[][] mediaData() { return new Object[][]{ new Object[]{WxConsts.MediaFileType.IMAGE, TestConstants.FILE_JPG, "mm.jpeg"}, - new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_MP3, "mm.mp3"}, - new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_AMR, "mm.amr"},//{"errcode":301017,"errmsg":"voice file only support amr like myvoice.amr"} + new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_MP3, "mm.mp3"},//{"errcode":301017,"errmsg":"voice file only support amr like myvoice.amr"} + new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_AMR, "mm.amr"}, new Object[]{WxConsts.MediaFileType.VIDEO, TestConstants.FILE_MP4, "mm.mp4"}, new Object[]{WxConsts.MediaFileType.FILE, TestConstants.FILE_JPG, "mm.jpeg"} }; @@ -75,4 +76,10 @@ public class WxCpMediaServiceImplTest { System.out.println(file); } + @Test + public void testUploadImg() throws WxErrorException { + URL url = ClassLoader.getSystemResource("mm.jpeg"); + String res = this.wxService.getMediaService().uploadImg(new File(url.getFile())); + assertThat(res).isNotEmpty(); + } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java index 9babeb3f..6b671120 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java @@ -1,22 +1,23 @@ package me.chanjar.weixin.cp.api.impl; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.testng.annotations.*; + import com.google.common.collect.Lists; import com.google.inject.Inject; +import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.api.ApiTestModule; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.Gender; import me.chanjar.weixin.cp.bean.WxCpInviteResult; import me.chanjar.weixin.cp.bean.WxCpUser; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; +import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo; -import java.util.List; -import java.util.Map; - -import static org.testng.Assert.assertNotEquals; -import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.*; /** *
@@ -109,4 +110,11 @@ public class WxCpUserServiceImplTest {
     System.out.println(result);
     assertNotNull(result);
   }
+
+  @Test
+  public void testGetExternalContact() throws WxErrorException {
+    WxCpUserExternalContactInfo result = this.wxCpService.getUserService().getExternalContact(userId);
+    System.out.println(result);
+    assertNotNull(result);
+  }
 }
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpAgentTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpAgentTest.java
index 6a2b87c5..74b8269d 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpAgentTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpAgentTest.java
@@ -14,11 +14,11 @@ public class WxCpAgentTest {
 
     WxCpAgent wxCpAgent = WxCpAgent.fromJson(json);
 
-    Assert.assertEquals(9, wxCpAgent.getAgentid().intValue());
+    Assert.assertEquals(9, wxCpAgent.getAgentId().intValue());
 
-    Assert.assertEquals(new Integer[]{42762742}, wxCpAgent.getAllowPartys().getPartyids().toArray());
+    Assert.assertEquals(new Integer[]{42762742}, wxCpAgent.getAllowParties().getPartyIds().toArray());
 
-    Assert.assertEquals(new Integer[]{23, 22, 35, 19, 32, 125, 133, 46, 150, 38, 183, 9, 7}, wxCpAgent.getAllowTags().getTagids().toArray());
+    Assert.assertEquals(new Integer[]{23, 22, 35, 19, 32, 125, 133, 46, 150, 38, 183, 9, 7}, wxCpAgent.getAllowTags().getTagIds().toArray());
 
   }
 
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactInfoTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactInfoTest.java
new file mode 100644
index 00000000..3c1b327c
--- /dev/null
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactInfoTest.java
@@ -0,0 +1,129 @@
+package me.chanjar.weixin.cp.bean;
+
+import java.util.List;
+
+import org.testng.annotations.*;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * 
+ *
+ * Created by Binary Wang on 2018/9/16.
+ * 
+ * + * @author Binary Wang + */ +public class WxCpUserExternalContactInfoTest { + + @Test + public void testFromJson() { + final String json = "{\n" + + " \"errcode\": 0,\n" + + " \"errmsg\": \"ok\",\n" + + " \"external_contact\": {\n" + + " \"external_userid\": \"woAJ2GCAAAXtWyujaWJHDDGi0mACH71w\",\n" + + " \"name\": \"李四\",\n" + + " \"position\": \"Mangaer\",\n" + + " \"avatar\": \"http://p.qlogo.cn/bizmail/IcsdgagqefergqerhewSdage/0\",\n" + + " \"corp_name\": \"腾讯\",\n" + + " \"corp_full_name\": \"腾讯科技有限公司\",\n" + + " \"type\": 2,\n" + + " \"gender\": 1,\n" + + " \"unionid\": \"ozynqsulJFCZ2z1aYeS8h-nuasdfR1\",\n" + + " \"external_profile\": {\n" + + " \"external_attr\": [\n" + + " {\n" + + " \"type\": 0,\n" + + " \"name\": \"文本名称\",\n" + + " \"text\": {\n" + + " \"value\": \"文本\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"type\": 1,\n" + + " \"name\": \"网页名称\",\n" + + " \"web\": {\n" + + " \"url\": \"http://www.test.com\",\n" + + " \"title\": \"标题\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"type\": 2,\n" + + " \"name\": \"测试app\",\n" + + " \"miniprogram\": {\n" + + " \"appid\": \"wx8bd80126147df384\",\n" + + " \"pagepath\": \"/index\",\n" + + " \"title\": \"my miniprogram\"\n" + + " }\n" + + " }\n" + + " ]\n" + + " }\n" + + " },\n" + + " \"follow_user\": [\n" + + " {\n" + + " \"userid\": \"rocky\",\n" + + " \"remark\": \"李部长\",\n" + + " \"description\": \"对接采购事物\",\n" + + " \"createtime\": 1525779812\n" + + " },\n" + + " {\n" + + " \"userid\": \"tommy\",\n" + + " \"remark\": \"李总\",\n" + + " \"description\": \"采购问题咨询\",\n" + + " \"createtime\": 1525881637\n" + + " }\n" + + " ]\n" + + "}"; + + final WxCpUserExternalContactInfo contactInfo = WxCpUserExternalContactInfo.fromJson(json); + assertThat(contactInfo).isNotNull(); + assertThat(contactInfo.getExternalContact()).isNotNull(); + + assertThat(contactInfo.getExternalContact().getExternalUserId()).isEqualTo("woAJ2GCAAAXtWyujaWJHDDGi0mACH71w"); + assertThat(contactInfo.getExternalContact().getPosition()).isEqualTo("Mangaer"); + assertThat(contactInfo.getExternalContact().getAvatar()).isEqualTo("http://p.qlogo.cn/bizmail/IcsdgagqefergqerhewSdage/0"); + assertThat(contactInfo.getExternalContact().getCorpName()).isEqualTo("腾讯"); + assertThat(contactInfo.getExternalContact().getCorpFullName()).isEqualTo("腾讯科技有限公司"); + assertThat(contactInfo.getExternalContact().getType()).isEqualTo(2); + assertThat(contactInfo.getExternalContact().getGender()).isEqualTo(1); + assertThat(contactInfo.getExternalContact().getUnionId()).isEqualTo("ozynqsulJFCZ2z1aYeS8h-nuasdfR1"); + assertThat(contactInfo.getExternalContact().getName()).isEqualTo("李四"); + + assertThat(contactInfo.getExternalContact().getExternalProfile()).isNotNull(); + + final List externalAttrs = contactInfo.getExternalContact().getExternalProfile().getExternalAttrs(); + assertThat(externalAttrs).isNotEmpty(); + + final WxCpUserExternalContactInfo.ExternalAttribute externalAttr1 = externalAttrs.get(0); + assertThat(externalAttr1.getType()).isEqualTo(0); + assertThat(externalAttr1.getName()).isEqualTo("文本名称"); + assertThat(externalAttr1.getText().getValue()).isEqualTo("文本"); + + final WxCpUserExternalContactInfo.ExternalAttribute externalAttr2 = externalAttrs.get(1); + assertThat(externalAttr2.getType()).isEqualTo(1); + assertThat(externalAttr2.getName()).isEqualTo("网页名称"); + assertThat(externalAttr2.getWeb().getUrl()).isEqualTo("http://www.test.com"); + assertThat(externalAttr2.getWeb().getTitle()).isEqualTo("标题"); + + final WxCpUserExternalContactInfo.ExternalAttribute externalAttr3 = externalAttrs.get(2); + assertThat(externalAttr3.getType()).isEqualTo(2); + assertThat(externalAttr3.getName()).isEqualTo("测试app"); + assertThat(externalAttr3.getMiniProgram().getAppid()).isEqualTo("wx8bd80126147df384"); + assertThat(externalAttr3.getMiniProgram().getPagePath()).isEqualTo("/index"); + assertThat(externalAttr3.getMiniProgram().getTitle()).isEqualTo("my miniprogram"); + + + List followedUsers = contactInfo.getFollowedUsers(); + assertThat(followedUsers).isNotEmpty(); + assertThat(followedUsers.get(0).getUserId()).isEqualTo("rocky"); + assertThat(followedUsers.get(0).getRemark()).isEqualTo("李部长"); + assertThat(followedUsers.get(0).getDescription()).isEqualTo("对接采购事物"); + assertThat(followedUsers.get(0).getCreateTime()).isEqualTo(1525779812); + + assertThat(followedUsers.get(1).getUserId()).isEqualTo("tommy"); + assertThat(followedUsers.get(1).getRemark()).isEqualTo("李总"); + assertThat(followedUsers.get(1).getDescription()).isEqualTo("采购问题咨询"); + assertThat(followedUsers.get(1).getCreateTime()).isEqualTo(1525881637); + } +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java index a9ab309c..ff204a80 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java @@ -1,6 +1,16 @@ package me.chanjar.weixin.cp.demo; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; + +import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.cp.WxCpConsts; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; @@ -9,13 +19,6 @@ import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; import me.chanjar.weixin.cp.config.WxCpConfigStorage; import me.chanjar.weixin.cp.message.WxCpMessageHandler; import me.chanjar.weixin.cp.message.WxCpMessageRouter; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.servlet.ServletHandler; -import org.eclipse.jetty.servlet.ServletHolder; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; public class WxCpDemoServer { @@ -78,9 +81,26 @@ public class WxCpDemoServer { }; wxCpMessageRouter = new WxCpMessageRouter(wxCpService); - wxCpMessageRouter.rule().async(false).content("哈哈") // 拦截内容为“哈哈”的消息 - .handler(handler).end().rule().async(false).content("oauth") - .handler(oauth2handler).end(); + wxCpMessageRouter.rule() + .async(false) + .content("哈哈") // 拦截内容为“哈哈”的消息 + .handler(handler) + .end() + .rule() + .async(false) + .content("oauth") + .handler(oauth2handler) + .end() + .rule() + .event(WxCpConsts.EventType.CHANGE_CONTACT) + .handler(new WxCpMessageHandler() { + @Override + public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context, WxCpService wxCpService, WxSessionManager sessionManager) throws WxErrorException { + System.out.println("通讯录发生变更"); + return null; + } + }) + .end(); } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapterTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapterTest.java new file mode 100644 index 00000000..ec553f75 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapterTest.java @@ -0,0 +1,124 @@ +package me.chanjar.weixin.cp.util.json; + +import org.testng.annotations.*; + +import me.chanjar.weixin.cp.bean.WxCpUser; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + *
+ *
+ * Created by Binary Wang on 2018/9/16.
+ * 
+ * + * @author BinaryWang + */ +public class WxCpUserGsonAdapterTest { + + @Test + public void testDeserialize() { + final String userJson = "{\n" + + " \"errcode\": 0,\n" + + " \"errmsg\": \"ok\",\n" + + " \"userid\": \"zhangsan\",\n" + + " \"name\": \"李四\",\n" + + " \"department\": [1, 2],\n" + + " \"order\": [1, 2],\n" + + " \"position\": \"后台工程师\",\n" + + " \"mobile\": \"15913215421\",\n" + + " \"gender\": \"1\",\n" + + " \"email\": \"zhangsan@gzdev.com\",\n" + + " \"isleader\": 1,\n" + + " \"avatar\": \"http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0\",\n" + + " \"telephone\": \"020-123456\",\n" + + " \"enable\": 1,\n" + + " \"alias\": \"jackzhang\",\n" + + " \"extattr\": {\n" + + " \"attrs\": [{\n" + + " \"name\": \"爱好\",\n" + + " \"value\": \"旅游\"\n" + + " }, {\n" + + " \"name\": \"卡号\",\n" + + " \"value\": \"1234567234\"\n" + + " }]\n" + + " },\n" + + " \"status\": 1,\n" + + " \"qr_code\": \"https://open.work.weixin.qq.com/wwopen/userQRCode?vcode=xxx\",\n" + + " \"external_profile\": {\n" + + " \"external_attr\": [{\n" + + " \"type\": 0,\n" + + " \"name\": \"文本名称\",\n" + + " \"text\": {\n" + + " \"value\": \"文本\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"type\": 1,\n" + + " \"name\": \"网页名称\",\n" + + " \"web\": {\n" + + " \"url\": \"http://www.test.com\",\n" + + " \"title\": \"标题\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"type\": 2,\n" + + " \"name\": \"测试app\",\n" + + " \"miniprogram\": {\n" + + " \"appid\": \"wx8bd80126147df384\",\n" + + " \"pagepath\": \"/index\",\n" + + " \"title\": \"my miniprogram\"\n" + + " }\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + + final WxCpUser user = WxCpUser.fromJson(userJson); + assertThat(user).isNotNull(); + assertThat(user.getExternalAttrs()).isNotEmpty(); + + final WxCpUser.ExternalAttribute externalAttr1 = user.getExternalAttrs().get(0); + assertThat(externalAttr1.getType()).isEqualTo(0); + assertThat(externalAttr1.getName()).isEqualTo("文本名称"); + assertThat(externalAttr1.getValue()).isEqualTo("文本"); + + final WxCpUser.ExternalAttribute externalAttr2 = user.getExternalAttrs().get(1); + assertThat(externalAttr2.getType()).isEqualTo(1); + assertThat(externalAttr2.getName()).isEqualTo("网页名称"); + assertThat(externalAttr2.getUrl()).isEqualTo("http://www.test.com"); + assertThat(externalAttr2.getTitle()).isEqualTo("标题"); + + final WxCpUser.ExternalAttribute externalAttr3 = user.getExternalAttrs().get(2); + assertThat(externalAttr3.getType()).isEqualTo(2); + assertThat(externalAttr3.getName()).isEqualTo("测试app"); + assertThat(externalAttr3.getAppid()).isEqualTo("wx8bd80126147df384"); + assertThat(externalAttr3.getPagePath()).isEqualTo("/index"); + assertThat(externalAttr3.getTitle()).isEqualTo("my miniprogram"); + } + + @Test + public void testSerialize() { + WxCpUser user = new WxCpUser(); + user.addExternalAttr(WxCpUser.ExternalAttribute.builder() + .type(0) + .name("文本名称") + .value("文本") + .build()); + user.addExternalAttr(WxCpUser.ExternalAttribute.builder() + .type(1) + .name("网页名称") + .url("http://www.test.com") + .title("标题") + .build()); + user.addExternalAttr(WxCpUser.ExternalAttribute.builder() + .type(2) + .name("测试app") + .appid("wx8bd80126147df384") + .pagePath("/index") + .title("my miniprogram") + .build()); + + assertThat(user.toJson()).isEqualTo("{\"external_profile\":{\"external_attr\":[{\"type\":0,\"name\":\"文本名称\",\"text\":{\"value\":\"文本\"}},{\"type\":1,\"name\":\"网页名称\",\"web\":{\"url\":\"http://www.test.com\",\"title\":\"标题\"}},{\"type\":2,\"name\":\"测试app\",\"miniprogram\":{\"appid\":\"wx8bd80126147df384\",\"pagepath\":\"/index\",\"title\":\"my miniprogram\"}}]}}"); + } +} diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index 571a30a0..45614761 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 3.1.0 + 3.2.0 weixin-java-miniapp Weixin Java Tools - MiniApp diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCodeService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCodeService.java index eb90c125..fbe08184 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCodeService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCodeService.java @@ -1,5 +1,7 @@ package cn.binarywang.wx.miniapp.api; +import java.util.List; + import cn.binarywang.wx.miniapp.bean.code.WxMaCategory; import cn.binarywang.wx.miniapp.bean.code.WxMaCodeAuditStatus; import cn.binarywang.wx.miniapp.bean.code.WxMaCodeCommitRequest; @@ -7,8 +9,6 @@ import cn.binarywang.wx.miniapp.bean.code.WxMaCodeSubmitAuditRequest; import cn.binarywang.wx.miniapp.bean.code.WxMaCodeVersionDistribution; import me.chanjar.weixin.common.error.WxErrorException; -import java.util.List; - /** * 小程序代码管理相关 API(大部分只能是第三方平台调用) * 文档:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1489140610_Uavc4&token=&lang=zh_CN @@ -44,11 +44,15 @@ public interface WxMaCodeService { /** * 获取体验小程序的体验二维码 + * 文档地址: + * https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1489140610_Uavc4&token=&lang=zh_CN * + * @param path 指定体验版二维码跳转到某个具体页面(如果不需要的话,则不需要填path参数,可在路径后以“?参数”方式传入参数) + * 具体的路径加参数需要urlencode(方法内部处理),比如page/index?action=1编码后得到page%2Findex%3Faction%3D1 * @return 二维码 bytes * @throws WxErrorException 上传失败时抛出,具体错误码请看类注释文档 */ - byte[] getQrCode() throws WxErrorException; + byte[] getQrCode(String path) throws WxErrorException; /** * 获取授权小程序帐号的可选类目 diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaJsapiService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaJsapiService.java new file mode 100644 index 00000000..156fcbc1 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaJsapiService.java @@ -0,0 +1,48 @@ +package cn.binarywang.wx.miniapp.api; + +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.error.WxErrorException; + +/** + *
+ *  jsapi相关接口
+ *  Created by BinaryWang on 2018/8/5.
+ * 
+ * + * @author Binary Wang + */ +public interface WxMaJsapiService { + /** + * 获得jsapi_ticket的url + */ + String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; + + /** + * 获得jsapi_ticket,不强制刷新jsapi_ticket + * + * @see #getJsapiTicket(boolean) + */ + String getJsapiTicket() throws WxErrorException; + + /** + *
+   * 获得jsapi_ticket
+   * 获得时会检查jsapiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
+   *
+   * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
+   * 
+ * + * @param forceRefresh 强制刷新 + */ + String getJsapiTicket(boolean forceRefresh) throws WxErrorException; + + /** + *
+   * 创建调用jsapi时所需要的签名
+   *
+   * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
+   * 
+ */ + WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMsgService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMsgService.java index 3adf883c..a838417e 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMsgService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMsgService.java @@ -2,6 +2,7 @@ package cn.binarywang.wx.miniapp.api; import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import cn.binarywang.wx.miniapp.bean.WxMaUniformMessage; import me.chanjar.weixin.common.error.WxErrorException; /** @@ -14,6 +15,7 @@ import me.chanjar.weixin.common.error.WxErrorException; public interface WxMaMsgService { String KEFU_MESSAGE_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/custom/send"; String TEMPLATE_MSG_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send"; + String UNIFORM_MSG_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send"; /** *
@@ -32,4 +34,14 @@ public interface WxMaMsgService {
    * 
*/ void sendTemplateMsg(WxMaTemplateMessage templateMessage) throws WxErrorException; + + + /** + *
+   * 下发小程序和公众号统一的服务消息
+   * 详情请见: 下发小程序和公众号统一的服务消息
+   * 接口url格式:https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
+   * 
+ */ + void sendUniformMsg(WxMaUniformMessage uniformMessage) throws WxErrorException; } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java index e89929ca..0904d606 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java @@ -1,5 +1,7 @@ package cn.binarywang.wx.miniapp.api; +import java.io.File; + import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import cn.binarywang.wx.miniapp.config.WxMaConfig; import me.chanjar.weixin.common.error.WxErrorException; @@ -17,12 +19,25 @@ public interface WxMaService { String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; String JSCODE_TO_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session"; + + String IMG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/img_sec_check"; + + /** + *
+   * 校验一张图片是否含有违法违规内容.
+   * 应用场景举例:1)图片智能鉴黄:涉及拍照的工具类应用(如美拍,识图类应用)用户拍照上传检测;电商类商品上架图片检测;媒体类用户文章里的图片检测等;2)敏感人脸识别:用户头像;媒体类用户文章里的图片检测;社交类用户上传的图片检测等。频率限制:单个 appId 调用上限为 1000 次/分钟,100,000 次/天
+   * 详情请见: https://developers.weixin.qq.com/miniprogram/dev/api/imgSecCheck.html
+   * 
+ */ + boolean imgSecCheck(File file) throws WxErrorException; + /** - * 获取登录后的session信息 + * 获取登录后的session信息. * * @param jsCode 登录时获取的 code */ WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException; + /** *
    * 验证消息的确来自微信服务器.
@@ -131,6 +146,7 @@ public interface WxMaService {
 
   /**
    * 返回模板配置相关接口方法的实现类对象, 以方便调用其各个接口.
+   *
    * @return WxMaTemplateService
    */
   WxMaTemplateService getTemplateService();
@@ -149,6 +165,13 @@ public interface WxMaService {
    */
   WxMaCodeService getCodeService();
 
+  /**
+   * 返回jsapi操作相关的 API服务类对象
+   *
+   * @return WxMaJsapiService
+   */
+  WxMaJsapiService getJsapiService();
+
   /**
    * 小程序修改服务器地址、成员管理 API
    *
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java
index 8c567218..a4abdc04 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java
@@ -5,6 +5,8 @@ import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
 import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
 import me.chanjar.weixin.common.error.WxErrorException;
 
+import java.util.Map;
+
 /**
  * 用户信息相关操作接口.
  *
@@ -28,6 +30,16 @@ public interface WxMaUserService {
    */
   WxMaUserInfo getUserInfo(String sessionKey, String encryptedData, String ivStr);
 
+  /**
+   * 上报用户数据后台接口.
+   * 

小游戏可以通过本接口上报key-value数据到用户的CloudStorage。

+ * 文档参考https://developers.weixin.qq.com/minigame/dev/document/open-api/data/setUserStorage.html + * @param kvMap 要上报的数据 + * @param sessionKey 通过wx.login 获得的登录态 + * @param openid + */ + void setUserStorage(Map kvMap, String sessionKey, String openid) throws WxErrorException; + /** * 解密用户手机号信息. * diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCodeServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCodeServiceImpl.java index 199d140a..a460f4a3 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCodeServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCodeServiceImpl.java @@ -1,5 +1,15 @@ package cn.binarywang.wx.miniapp.api.impl; +import java.io.File; +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; + import cn.binarywang.wx.miniapp.api.WxMaCodeService; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.bean.code.WxMaCategory; @@ -17,12 +27,6 @@ import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.json.GsonHelper; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - /** * @author Charming * @since 2018-04-26 20:00 @@ -41,13 +45,19 @@ public class WxMaCodeServiceImpl implements WxMaCodeService { } @Override - public byte[] getQrCode() throws WxErrorException { + public byte[] getQrCode(String path) throws WxErrorException { String appId = this.wxMaService.getWxMaConfig().getAppid(); Path qrCodeFilePath = null; try { RequestExecutor executor = BaseMediaDownloadRequestExecutor .create(this.wxMaService.getRequestHttp(), Files.createTempDirectory("weixin-java-tools-ma-" + appId).toFile()); - qrCodeFilePath = this.wxMaService.execute(executor, GET_QRCODE_URL, null).toPath(); + + final StringBuilder url = new StringBuilder(GET_QRCODE_URL); + if (StringUtils.isNotBlank(path)) { + url.append("?path=").append(URLEncoder.encode(path, StandardCharsets.UTF_8.name())); + } + + qrCodeFilePath = this.wxMaService.execute(executor, url.toString(), null).toPath(); return Files.readAllBytes(qrCodeFilePath); } catch (IOException e) { throw new WxErrorException(WxError.builder().errorMsg(e.getMessage()).build(), e); diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaJsapiServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaJsapiServiceImpl.java new file mode 100644 index 00000000..8164db8b --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaJsapiServiceImpl.java @@ -0,0 +1,75 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaJsapiService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.RandomUtils; +import me.chanjar.weixin.common.util.crypto.SHA1; + +import java.util.concurrent.locks.Lock; + +/** + *
+ *  Created by BinaryWang on 2018/8/5.
+ * 
+ * + * @author Binary Wang + */ +public class WxMaJsapiServiceImpl implements WxMaJsapiService { + private static final JsonParser JSON_PARSER = new JsonParser(); + + private WxMaService wxMaService; + + public WxMaJsapiServiceImpl(WxMaService wxMaService) { + this.wxMaService = wxMaService; + } + + @Override + public String getJsapiTicket() throws WxErrorException { + return getJsapiTicket(false); + } + + @Override + public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { + Lock lock = this.wxMaService.getWxMaConfig().getJsapiTicketLock(); + try { + lock.lock(); + if (forceRefresh) { + this.wxMaService.getWxMaConfig().expireJsapiTicket(); + } + + if (this.wxMaService.getWxMaConfig().isJsapiTicketExpired()) { + String responseContent = this.wxMaService.get(GET_JSAPI_TICKET_URL, null); + JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); + JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); + String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); + int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); + this.wxMaService.getWxMaConfig().updateJsapiTicket(jsapiTicket, expiresInSeconds); + } + } finally { + lock.unlock(); + } + return this.wxMaService.getWxMaConfig().getJsapiTicket(); + } + + @Override + public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { + long timestamp = System.currentTimeMillis() / 1000; + String randomStr = RandomUtils.getRandomStr(); + String jsapiTicket = getJsapiTicket(false); + String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket, + "noncestr=" + randomStr, "timestamp=" + timestamp, "url=" + url); + return WxJsapiSignature + .builder() + .appId(this.wxMaService.getWxMaConfig().getAppid()) + .timestamp(timestamp) + .nonceStr(randomStr) + .url(url) + .signature(signature) + .build(); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java index 0a397125..e0403a51 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java @@ -4,6 +4,7 @@ import cn.binarywang.wx.miniapp.api.WxMaMsgService; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import cn.binarywang.wx.miniapp.bean.WxMaUniformMessage; import cn.binarywang.wx.miniapp.constant.WxMaConstants; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -36,4 +37,13 @@ public class WxMaMsgServiceImpl implements WxMaMsgService { } } + @Override + public void sendUniformMsg(WxMaUniformMessage uniformMessage) throws WxErrorException { + String responseContent = this.wxMaService.post(UNIFORM_MSG_SEND_URL, uniformMessage.toJson()); + JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); + if (jsonObject.get(WxMaConstants.ERRCODE).getAsInt() != 0) { + throw new WxErrorException(WxError.fromJson(responseContent)); + } + } + } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java index be9dff69..9c8ac82d 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java @@ -1,7 +1,23 @@ package cn.binarywang.wx.miniapp.api.impl; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.Lock; + +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.CloseableHttpClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import cn.binarywang.wx.miniapp.api.WxMaAnalysisService; import cn.binarywang.wx.miniapp.api.WxMaCodeService; +import cn.binarywang.wx.miniapp.api.WxMaJsapiService; import cn.binarywang.wx.miniapp.api.WxMaMediaService; import cn.binarywang.wx.miniapp.api.WxMaMsgService; import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; @@ -12,31 +28,21 @@ import cn.binarywang.wx.miniapp.api.WxMaUserService; import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import cn.binarywang.wx.miniapp.config.WxMaConfig; import com.google.common.base.Joiner; +import com.google.gson.Gson; import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.DataUtils; import me.chanjar.weixin.common.util.crypto.SHA1; import me.chanjar.weixin.common.util.http.HttpType; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.BasicResponseHandler; -import org.apache.http.impl.client.CloseableHttpClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.locks.Lock; import static cn.binarywang.wx.miniapp.constant.WxMaConstants.ErrorCode.*; @@ -58,10 +64,13 @@ public class WxMaServiceImpl implements WxMaService, RequestHttpBinary Wang @@ -30,6 +41,30 @@ public class WxMaUserServiceImpl implements WxMaUserService { return WxMaUserInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr)); } + @Override + public void setUserStorage(Map kvMap, String sessionKey, String openid) throws WxErrorException { + final WxMaConfig config = this.service.getWxMaConfig(); + JsonObject param = new JsonObject(); + JsonArray array = new JsonArray(); + for (Map.Entry e : kvMap.entrySet()) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("key", e.getKey()); + jsonObject.addProperty("value", e.getValue()); + array.add(jsonObject); + } + param.add("kv_list", array); + String params = param.toString(); + String signature = SignUtils.createHmacSha256Sign(params, sessionKey); + String url = String.format("https://api.weixin.qq.com/wxa/set_user_storage" + + "?appid=%s&signature=%s&openid=%s&sig_method=%s", + config.getAppid(), signature, openid, "hmac_sha256"); + String result = this.service.post(url, params); + WxError error = WxError.fromJson(result); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + } + @Override public WxMaPhoneNumberInfo getPhoneNoInfo(String sessionKey, String encryptedData, String ivStr) { return WxMaPhoneNumberInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr)); diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java index d04212d4..d44d1556 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java @@ -1,5 +1,14 @@ package cn.binarywang.wx.miniapp.bean; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.nio.charset.StandardCharsets; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import cn.binarywang.wx.miniapp.config.WxMaConfig; import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; @@ -8,14 +17,7 @@ import com.google.gson.annotations.SerializedName; import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamConverter; import lombok.Data; -import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.nio.charset.StandardCharsets; /** * @author Binary Wang @@ -166,7 +168,7 @@ public class WxMaMessage implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } public String toJson() { diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateData.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateData.java new file mode 100644 index 00000000..5eae34b1 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateData.java @@ -0,0 +1,32 @@ +package cn.binarywang.wx.miniapp.bean; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + *
+ *
+ * Created by Binary Wang on 2018/9/23.
+ * 
+ * + * @author Binary Wang + */ +@Data +@NoArgsConstructor +public class WxMaTemplateData { + private String name; + private String value; + private String color; + + public WxMaTemplateData(String name, String value) { + this.name = name; + this.value = value; + } + + public WxMaTemplateData(String name, String value, String color) { + this.name = name; + this.value = value; + this.color = color; + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessage.java index 23f3988f..5a674394 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessage.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessage.java @@ -1,12 +1,16 @@ package cn.binarywang.wx.miniapp.bean; -import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; -import lombok.*; - import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + /** * 模板消息. * 参考 https://mp.weixin.qq.com/debug/wxadoc/dev/api/notice.html#接口说明 模板消息部分 @@ -69,7 +73,7 @@ public class WxMaTemplateMessage implements Serializable { * 描述: 模板内容,不填则下发空模板 *
*/ - private List data; + private List data; /** * 模板内容字体的颜色,不填默认黑色. @@ -91,7 +95,7 @@ public class WxMaTemplateMessage implements Serializable { */ private String emphasisKeyword; - public WxMaTemplateMessage addData(Data datum) { + public WxMaTemplateMessage addData(WxMaTemplateData datum) { if (this.data == null) { this.data = new ArrayList<>(); } @@ -104,23 +108,4 @@ public class WxMaTemplateMessage implements Serializable { return WxMaGsonBuilder.create().toJson(this); } - @lombok.Data - public static class Data { - private String name; - private String value; - private String color; - - public Data(String name, String value) { - this.name = name; - this.value = value; - } - - public Data(String name, String value, String color) { - this.name = name; - this.value = value; - this.color = color; - } - - } - } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaUniformMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaUniformMessage.java new file mode 100644 index 00000000..e58ad58a --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaUniformMessage.java @@ -0,0 +1,108 @@ +package cn.binarywang.wx.miniapp.bean; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * 模板消息. + * 参考 https://mp.weixin.qq.com/debug/wxadoc/dev/api/notice.html#接口说明 模板消息部分 + * + * @author Binary Wang + */ +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class WxMaUniformMessage implements Serializable { + private static final long serialVersionUID = 5063374783759519418L; + + /** + * 是否发送公众号模版消息,否则发送小程序模版消息. + */ + private boolean isMpTemplateMsg; + + /** + * 用户openid. + * 可以是小程序的openid,也可以是mp_template_msg.appid对应的公众号的openid + */ + private String toUser; + + /** + * 公众号appid,要求与小程序有绑定且同主体. + */ + private String appid; + + /** + * 公众号或小程序模板ID. + */ + private String templateId; + + /** + * 公众号模板消息所要跳转的url. + */ + private String url; + + /** + * 小程序页面路径. + */ + private String page; + + /** + * 小程序模板消息formid. + */ + private String formId; + + /** + * 公众号模板消息所要跳转的小程序,小程序的必须与公众号具有绑定关系. + */ + private MiniProgram miniProgram; + + /** + * 小程序模板数据. + */ + private List data; + + /** + * 模板需要放大的关键词,不填则默认无放大. + */ + private String emphasisKeyword; + + public WxMaUniformMessage addData(WxMaTemplateData datum) { + if (this.data == null) { + this.data = new ArrayList<>(); + } + this.data.add(datum); + + return this; + } + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class MiniProgram implements Serializable { + private static final long serialVersionUID = -7945254706501974849L; + + private String appid; + private String pagePath; + + /** + * 是否使用path,否则使用pagepath. + * 加入此字段是基于微信官方接口变化多端的考虑 + */ + private boolean usePath = false; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/code/WxMaCodeExtConfig.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/code/WxMaCodeExtConfig.java index 51211123..5d0314b2 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/code/WxMaCodeExtConfig.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/code/WxMaCodeExtConfig.java @@ -1,14 +1,15 @@ package cn.binarywang.wx.miniapp.bean.code; -import lombok.Builder; -import lombok.Data; - import java.io.Serializable; import java.util.List; import java.util.Map; +import lombok.Builder; +import lombok.Data; + /** * 上传代码需要用到的第三方自定义的配置 + * 详细文档,参考:https://developers.weixin.qq.com/miniprogram/dev/framework/config.html * * @author Charming * @since 2018-04-26 19:44 @@ -18,34 +19,34 @@ import java.util.Map; public class WxMaCodeExtConfig implements Serializable { private static final long serialVersionUID = -7666911367458178753L; /** - * 配置 ext.json 是否生效 + * 配置 ext.json 是否生效. * 必填:是 */ private boolean extEnable; /** - * 配置 extAppid + * 配置 extAppid. * 必填:是 */ private String extAppid; /** - * 开发自定义的数据字段 + * 开发自定义的数据字段. * 必填:否 */ private Object ext; /** - * 单独设置每个页面的 json + * 单独设置每个页面的 json. * 必填:否 * key: page 名称,如 pages/logs/logs * value: page 配置 */ private Map extPages; /** - * 是否直接提交到待审核列表 + * 是否直接提交到待审核列表. * 必填:否 */ private Boolean directCommit; /** - * 设置页面路径(同 app.json 相同的字段,填写会覆盖 app.json) + * 设置页面路径(同 app.json 相同的字段,填写会覆盖 app.json). * 必填:否 */ private List pages; @@ -64,6 +65,11 @@ public class WxMaCodeExtConfig implements Serializable { * 必填:否 */ private Boolean debug; + /** + * 底部 tab 栏的表现. + * 必填:否 + */ + private TabBar tabBar; /** * page.json 配置,页面配置 @@ -73,125 +79,125 @@ public class WxMaCodeExtConfig implements Serializable { @Builder public static class PageConfig { /** - * 导航栏背景颜色,如"#000000" HexColor + * 导航栏背景颜色,如"#000000" HexColor. * 默认:#000000 */ private String navigationBarBackgroundColor; /** - * 导航栏标题颜色,仅支持 black/white + * 导航栏标题颜色,仅支持 black/white. * 默认:white */ private String navigationBarTextStyle; /** - * 导航栏标题文字内容 + * 导航栏标题文字内容. */ private String navigationBarTitleText; /** - * 窗口的背景色 HexColor + * 窗口的背景色 HexColor. * 默认:#ffffff */ private String backgroundColor; /** - * 下拉背景字体、loading 图的样式,仅支持 dark/light + * 下拉背景字体、loading 图的样式,仅支持 dark/light. * 默认:dark */ private String backgroundTextStyle; /** - * 是否开启下拉刷新,详见页面相关事件处理函数 + * 是否开启下拉刷新,详见页面相关事件处理函数. * 默认:false */ private String enablePullDownRefresh; /** - * 设置为 true 则页面整体不能上下滚动;只在 page.json 中有效,无法在 app.json 中设置该项 + * 设置为 true 则页面整体不能上下滚动;只在 page.json 中有效,无法在 app.json 中设置该项. * 默认:false */ private Boolean disableScroll; /** - * 页面上拉触底事件触发时距页面底部距离,单位为px + * 页面上拉触底事件触发时距页面底部距离,单位为px. * 默认:50 */ private Integer onReachBottomDistance; } /** - * tabBar 配置 + * tabBar 配置. */ @Data @Builder public static class TabBar { /** - * HexColor, tab 上的文字默认颜色 + * HexColor, tab 上的文字默认颜色. */ private String color; /** - * HexColor, tab 上的文字选中时的颜色 + * HexColor, tab 上的文字选中时的颜色. */ private String selectedColor; /** - * HexColor, tab 的背景色 + * HexColor, tab 的背景色. */ private String backgroundColor; /** - * tabbar 上边框的颜色,仅支持 black/white + * tabbar 上边框的颜色,仅支持 black/white. */ private String borderStyle; /** - * tab 的列表,最少2个、最多5个 tab + * tab 的列表,最少2个、最多5个 tab. */ private List list; /** - * 可选值 bottom、top + * 可选值 bottom、top. */ private String position; /** - * list item + * list item. */ @Data @Builder public static class Item { /** - * 是 页面路径,必须在 pages 中先定义 + * 页面路径,必须在 pages 中先定义. */ private String pagePath; /** - * tab 上按钮文字 + * tab 上按钮文字. */ private String text; /** - * 图片路径,icon 大小限制为40kb,建议尺寸为 81px * 81px,当 postion 为 top 时,此参数无效,不支持网络图片 + * 图片路径,icon 大小限制为40kb,建议尺寸为 81px * 81px,当 postion 为 top 时,此参数无效,不支持网络图片. */ private String iconPath; /** - * 选中时的图片路径,icon 大小限制为40kb,建议尺寸为 81px * 81px ,当 postion 为 top 时,此参数无效 + * 选中时的图片路径,icon 大小限制为40kb,建议尺寸为 81px * 81px ,当 postion 为 top 时,此参数无效. */ private String selectedIconPath; } } /** - * 各种网络请求的超时时间 + * 各种网络请求的超时时间. */ @Data @Builder public static class NetworkTimeout { /** - * wx.request的超时时间,单位毫秒,默认为:60000 + * wx.request的超时时间,单位毫秒,默认为:60000. * 必填:否 */ private Integer request; /** - * wx.connectSocket的超时时间,单位毫秒,默认为:60000 + * wx.connectSocket的超时时间,单位毫秒,默认为:60000. * 必填:否 */ private Integer connectSocket; /** - * wx.uploadFile的超时时间,单位毫秒,默认为:60000 + * wx.uploadFile的超时时间,单位毫秒,默认为:60000. * 必填:否 */ private Integer uploadFile; /** - * wx.downloadFile的超时时间,单位毫秒,默认为:60000 + * wx.downloadFile的超时时间,单位毫秒,默认为:60000. * 必填:否 */ private Integer downloadFile; diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java index df72bb2c..915cffdd 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java @@ -38,6 +38,25 @@ public interface WxMaConfig { */ void updateAccessToken(String accessToken, int expiresInSeconds); + String getJsapiTicket(); + + Lock getJsapiTicketLock(); + + boolean isJsapiTicketExpired(); + + /** + * 强制将jsapi ticket过期掉 + */ + void expireJsapiTicket(); + + /** + * 应该是线程安全的 + * + * @param jsapiTicket 新的jsapi ticket值 + * @param expiresInSeconds 过期时间,以秒为单位 + */ + void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); + String getAppid(); String getSecret(); diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInMemoryConfig.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInMemoryConfig.java index 7d84c90f..d8e286af 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInMemoryConfig.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInMemoryConfig.java @@ -1,13 +1,15 @@ package cn.binarywang.wx.miniapp.config; -import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.ToStringUtils; -import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; - import java.io.File; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; + /** * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 * @@ -27,7 +29,11 @@ public class WxMaInMemoryConfig implements WxMaConfig { protected volatile String httpProxyUsername; protected volatile String httpProxyPassword; + protected volatile String jsapiTicket; + protected volatile long jsapiTicketExpiresTime; + protected Lock accessTokenLock = new ReentrantLock(); + protected Lock jsapiTicketLock = new ReentrantLock(); /** * 临时文件目录 @@ -70,6 +76,33 @@ public class WxMaInMemoryConfig implements WxMaConfig { this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; } + @Override + public String getJsapiTicket() { + return this.jsapiTicket; + } + + @Override + public Lock getJsapiTicketLock() { + return this.jsapiTicketLock; + } + + @Override + public boolean isJsapiTicketExpired() { + return System.currentTimeMillis() > this.jsapiTicketExpiresTime; + } + + @Override + public void expireJsapiTicket() { + this.jsapiTicketExpiresTime = 0; + } + + @Override + public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { + this.jsapiTicket = jsapiTicket; + // 预留200秒的时间 + this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + } + @Override public void expireAccessToken() { this.expiresTime = 0; @@ -158,7 +191,7 @@ public class WxMaInMemoryConfig implements WxMaConfig { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } @Override diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaGsonBuilder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaGsonBuilder.java index 21f48d3f..f01eb33d 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaGsonBuilder.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaGsonBuilder.java @@ -1,6 +1,7 @@ package cn.binarywang.wx.miniapp.util.json; import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import cn.binarywang.wx.miniapp.bean.WxMaUniformMessage; import cn.binarywang.wx.miniapp.bean.analysis.WxMaRetainInfo; import cn.binarywang.wx.miniapp.bean.analysis.WxMaUserPortrait; import cn.binarywang.wx.miniapp.bean.analysis.WxMaVisitDistribution; @@ -18,6 +19,7 @@ public class WxMaGsonBuilder { static { INSTANCE.disableHtmlEscaping(); INSTANCE.registerTypeAdapter(WxMaTemplateMessage.class, new WxMaTemplateMessageGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMaUniformMessage.class, new WxMaUniformMessageGsonAdapter()); INSTANCE.registerTypeAdapter(WxMaCodeCommitRequest.class, new WxMaCodeCommitRequestGsonAdapter()); INSTANCE.registerTypeAdapter(WxMaCodeVersionDistribution.class, new WxMaCodeVersionDistributionGsonAdapter()); INSTANCE.registerTypeAdapter(WxMaVisitDistribution.class, new WxMaVisitDistributionGsonAdapter()); diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaTemplateMessageGsonAdapter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaTemplateMessageGsonAdapter.java index 0b4edee2..800a7e5a 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaTemplateMessageGsonAdapter.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaTemplateMessageGsonAdapter.java @@ -1,13 +1,14 @@ package cn.binarywang.wx.miniapp.util.json; +import java.lang.reflect.Type; + +import cn.binarywang.wx.miniapp.bean.WxMaTemplateData; import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; -import java.lang.reflect.Type; - /** * @author Binary Wang */ @@ -26,10 +27,6 @@ public class WxMaTemplateMessageGsonAdapter implements JsonSerializerBinary Wang + */ +public class WxMaUniformMessageGsonAdapter implements JsonSerializer { + + @Override + public JsonElement serialize(WxMaUniformMessage message, Type typeOfSrc, JsonSerializationContext context) { + JsonObject messageJson = new JsonObject(); + messageJson.addProperty("touser", message.getToUser()); + if (message.isMpTemplateMsg()) { + JsonObject msg = new JsonObject(); + if (message.getAppid() != null) { + msg.addProperty("appid", message.getAppid()); + } + + msg.addProperty("template_id", message.getTemplateId()); + + if (message.getUrl() != null) { + msg.addProperty("url", message.getUrl()); + } + + final WxMaUniformMessage.MiniProgram miniProgram = message.getMiniProgram(); + if (miniProgram != null) { + JsonObject miniProgramJson = new JsonObject(); + miniProgramJson.addProperty("appid", miniProgram.getAppid()); + if (miniProgram.isUsePath()) { + miniProgramJson.addProperty("path", miniProgram.getPagePath()); + } else { + miniProgramJson.addProperty("pagepath", miniProgram.getPagePath()); + } + msg.add("miniprogram", miniProgramJson); + } + + if (message.getData() != null) { + JsonObject data = new JsonObject(); + for (WxMaTemplateData templateData : message.getData()) { + JsonObject dataJson = new JsonObject(); + dataJson.addProperty("value", templateData.getValue()); + if (templateData.getColor() != null) { + dataJson.addProperty("color", templateData.getColor()); + } + data.add(templateData.getName(), dataJson); + } + msg.add("data", data); + } + + + messageJson.add("mp_template_msg", msg); + return messageJson; + } + + //小程序模版消息 + JsonObject msg = new JsonObject(); + msg.addProperty("template_id", message.getTemplateId()); + + if (message.getPage() != null) { + msg.addProperty("page", message.getPage()); + } + + if (message.getFormId() != null) { + msg.addProperty("form_id", message.getFormId()); + } + + JsonObject data = new JsonObject(); + msg.add("data", data); + + if (message.getData() != null) { + for (WxMaTemplateData templateData : message.getData()) { + JsonObject dataJson = new JsonObject(); + dataJson.addProperty("value", templateData.getValue()); + if (templateData.getColor() != null) { + dataJson.addProperty("color", templateData.getColor()); + } + data.add(templateData.getName(), dataJson); + } + } + + if (message.getEmphasisKeyword() != null) { + msg.addProperty("emphasis_keyword", message.getEmphasisKeyword()); + } + + messageJson.add("weapp_template_msg", msg); + + return messageJson; + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaCodeServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaCodeServiceImplTest.java index 34c78899..0a4aca45 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaCodeServiceImplTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaCodeServiceImplTest.java @@ -1,5 +1,12 @@ package cn.binarywang.wx.miniapp.api.impl; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.testng.annotations.*; + import cn.binarywang.wx.miniapp.api.WxMaCodeService; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.bean.code.WxMaCategory; @@ -11,16 +18,8 @@ import cn.binarywang.wx.miniapp.bean.code.WxMaCodeVersionDistribution; import cn.binarywang.wx.miniapp.config.WxMaConfig; import cn.binarywang.wx.miniapp.test.ApiTestModule; import com.google.inject.Inject; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; +import static org.testng.Assert.*; /** * @author Charming @@ -77,7 +76,7 @@ public class WxMaCodeServiceImplTest { @Test public void testGetQrCode() throws Exception { - byte[] qrCode = wxService.getCodeService().getQrCode(); + byte[] qrCode = wxService.getCodeService().getQrCode(null); assertTrue(qrCode.length > 0); } diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaJsapiServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaJsapiServiceImplTest.java new file mode 100644 index 00000000..07f4358d --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaJsapiServiceImplTest.java @@ -0,0 +1,45 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.inject.Inject; +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.error.WxErrorException; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + *
+ *  Created by BinaryWang on 2018/8/5.
+ * 
+ * + * @author Binary Wang + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaJsapiServiceImplTest { + @Inject + private WxMaService wxService; + @Inject + private WxMaConfig wxMaConfig; + + @Test + public void testGetJsapiTicket() throws WxErrorException { + assertThat(this.wxService.getJsapiService().getJsapiTicket()).isNotBlank(); + } + + @Test + public void testGetJsapiTicket1() throws WxErrorException { + assertThat(this.wxService.getJsapiService().getJsapiTicket(true)).isNotBlank(); + } + + @Test + public void testCreateJsapiSignature() throws WxErrorException { + final WxJsapiSignature jsapiSignature = this.wxService.getJsapiService().createJsapiSignature("http://www.qq.com"); + System.out.println(jsapiSignature); + assertThat(jsapiSignature).isNotNull(); + } +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java index d05c031e..eb671cda 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java @@ -1,17 +1,20 @@ package cn.binarywang.wx.miniapp.api.impl; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.testng.annotations.*; + import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.bean.WxMaTemplateData; import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import cn.binarywang.wx.miniapp.bean.WxMaUniformMessage; import cn.binarywang.wx.miniapp.test.ApiTestModule; import cn.binarywang.wx.miniapp.test.TestConfig; import com.google.common.collect.Lists; import com.google.inject.Inject; import me.chanjar.weixin.common.error.WxErrorException; -import org.testng.annotations.*; - -import java.text.SimpleDateFormat; -import java.util.Date; /** * 测试消息相关接口 @@ -45,15 +48,33 @@ public class WxMaMsgServiceImplTest { .formId("FORMID") .page("index") .data(Lists.newArrayList( - new WxMaTemplateMessage.Data("keyword1", "339208499", "#173177"), - new WxMaTemplateMessage.Data("keyword2", dateFormat.format(new Date()), "#173177"), - new WxMaTemplateMessage.Data("keyword3", "粤海喜来登酒店", "#173177"), - new WxMaTemplateMessage.Data("keyword4", "广州市天河区天河路208号", "#173177"))) + new WxMaTemplateData("keyword1", "339208499", "#173177"), + new WxMaTemplateData("keyword2", dateFormat.format(new Date()), "#173177"), + new WxMaTemplateData("keyword3", "粤海喜来登酒店", "#173177"), + new WxMaTemplateData("keyword4", "广州市天河区天河路208号", "#173177"))) .templateId(config.getTemplateId()) .emphasisKeyword("keyword1.DATA") .build(); - //templateMessage.addData( new WxMaTemplateMessage.Data("keyword1", "339208499", "#173177")); + //templateMessage.addData( new WxMaTemplateData("keyword1", "339208499", "#173177")); this.wxService.getMsgService().sendTemplateMsg(templateMessage); } + @Test + public void testSendUniformMsg() throws WxErrorException { + TestConfig config = (TestConfig) this.wxService.getWxMaConfig(); + WxMaUniformMessage message = WxMaUniformMessage.builder() + .isMpTemplateMsg(false) + .toUser(config.getOpenid()) + .page("page/page/index") + .templateId("TEMPLATE_ID") + .formId("FORMID") + .emphasisKeyword("keyword1.DATA") + .build(); + message.addData(new WxMaTemplateData("keyword1", "339208499")) + .addData(new WxMaTemplateData("keyword2", "2015年01月05日 12:30")) + .addData(new WxMaTemplateData("keyword3", "腾讯微信总部")) + .addData(new WxMaTemplateData("keyword4", "广州市海珠区新港中路397号")); + + this.wxService.getMsgService().sendUniformMsg(message); + } } diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java index 1d7ec2f3..dcefc68c 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java @@ -1,16 +1,17 @@ package cn.binarywang.wx.miniapp.api.impl; +import java.io.File; + +import org.apache.commons.lang3.StringUtils; +import org.testng.annotations.*; + import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.config.WxMaConfig; import cn.binarywang.wx.miniapp.test.ApiTestModule; import com.google.inject.Inject; import me.chanjar.weixin.common.error.WxErrorException; -import org.apache.commons.lang3.StringUtils; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; -import static org.testng.Assert.assertNotEquals; -import static org.testng.Assert.assertTrue; +import static org.testng.Assert.*; /** * @author Binary Wang @@ -32,4 +33,9 @@ public class WxMaServiceImplTest { assertTrue(StringUtils.isNotBlank(after)); } + @Test + public void testImgSecCheck() throws WxErrorException { + boolean result = this.wxService.imgSecCheck(new File(ClassLoader.getSystemResource("tmp.png").getFile())); + assertTrue(result); + } } diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImplTest.java index 33e39a6b..2c478e8f 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImplTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImplTest.java @@ -1,5 +1,9 @@ package cn.binarywang.wx.miniapp.api.impl; +import cn.binarywang.wx.miniapp.test.TestConfig; +import com.google.common.collect.ImmutableMap; +import jdk.nashorn.internal.ir.annotations.Immutable; +import me.chanjar.weixin.common.error.WxErrorException; import org.testng.annotations.*; import cn.binarywang.wx.miniapp.api.WxMaService; @@ -8,6 +12,8 @@ import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; import cn.binarywang.wx.miniapp.test.ApiTestModule; import com.google.inject.Inject; +import javax.management.ImmutableDescriptor; + import static org.testng.Assert.*; /** @@ -54,4 +60,17 @@ public class WxMaUserServiceImplTest { assertNotNull(phoneNoInfo); System.out.println(phoneNoInfo.toString()); } + + @Test + public void testGetSessionInfo() { + } + + /** + * TODO 测试数据有问题,需要替换为正确的数据 + */ + @Test + public void testSetUserStorage() throws WxErrorException { + this.wxService.getUserService().setUserStorage(ImmutableMap.of("1","2"), + "r7BXXKkLb8qrSNn05n0qiA",((TestConfig)this.wxService.getWxMaConfig()).getOpenid()); + } } diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessageTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessageTest.java index d4464312..51eb0e87 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessageTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessageTest.java @@ -1,9 +1,10 @@ package cn.binarywang.wx.miniapp.bean; +import org.testng.annotations.*; + import com.google.common.collect.Lists; -import org.testng.annotations.Test; -import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.*; /** * @author Binary Wang @@ -17,10 +18,10 @@ public class WxMaTemplateMessageTest { .formId("FORMID") .page("index") .data(Lists.newArrayList( - new WxMaTemplateMessage.Data("keyword1", "339208499", "#173177"), - new WxMaTemplateMessage.Data("keyword2", "2015年01月05日12:30", "#173177"), - new WxMaTemplateMessage.Data("keyword3", "粤海喜来登酒店", "#173177"), - new WxMaTemplateMessage.Data("keyword4", "广州市天河区天河路208号", "#173177"))) + new WxMaTemplateData("keyword1", "339208499", "#173177"), + new WxMaTemplateData("keyword2", "2015年01月05日12:30", "#173177"), + new WxMaTemplateData("keyword3", "粤海喜来登酒店", "#173177"), + new WxMaTemplateData("keyword4", "广州市天河区天河路208号", "#173177"))) .templateId("TEMPLATE_ID") .emphasisKeyword("keyword1.DATA") .build(); diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java index bc4b13a1..fe886f4b 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java @@ -1,9 +1,20 @@ package cn.binarywang.wx.miniapp.demo; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; + import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import cn.binarywang.wx.miniapp.bean.WxMaTemplateData; import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; import cn.binarywang.wx.miniapp.config.WxMaConfig; import cn.binarywang.wx.miniapp.constant.WxMaConstants; @@ -14,15 +25,6 @@ import com.google.common.collect.Lists; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.session.WxSessionManager; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.servlet.ServletHandler; -import org.eclipse.jetty.servlet.ServletHolder; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; -import java.util.concurrent.locks.ReentrantLock; /** * @author Binary Wang @@ -96,7 +98,7 @@ public class WxMaDemoServer { throws WxErrorException { service.getMsgService().sendTemplateMsg(WxMaTemplateMessage.builder() .templateId(templateId).data(Lists.newArrayList( - new WxMaTemplateMessage.Data("keyword1", "339208499", "#173177"))) + new WxMaTemplateData("keyword1", "339208499", "#173177"))) .toUser(wxMessage.getFromUser()) .formId("自己替换可用的formid") .build()); diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/TestConfig.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/TestConfig.java index ee941ef3..6cebdeb2 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/TestConfig.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/TestConfig.java @@ -54,6 +54,7 @@ public class TestConfig extends WxMaInMemoryConfig { this.templateId = templateId; } + @Override public void setAccessTokenLock(Lock lock) { super.accessTokenLock = lock; } diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/util/json/WxMaUniformMessageGsonAdapterTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/util/json/WxMaUniformMessageGsonAdapterTest.java new file mode 100644 index 00000000..1541879c --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/util/json/WxMaUniformMessageGsonAdapterTest.java @@ -0,0 +1,112 @@ +package cn.binarywang.wx.miniapp.util.json; + +import org.testng.annotations.*; + +import cn.binarywang.wx.miniapp.bean.WxMaTemplateData; +import cn.binarywang.wx.miniapp.bean.WxMaUniformMessage; +import com.google.gson.JsonParser; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + *
+ *
+ * Created by Binary Wang on 2018/9/23.
+ * 
+ * + * @author Binary Wang + */ +public class WxMaUniformMessageGsonAdapterTest { + + @Test + public void testSerialize_mp() { + WxMaUniformMessage message = WxMaUniformMessage.builder() + .isMpTemplateMsg(true) + .toUser("OPENID") + .appid("APPID") + .templateId("TEMPLATE_ID") + .url("http://weixin.qq.com/download") + .miniProgram(new WxMaUniformMessage.MiniProgram("xiaochengxuappid12345", "index?foo=bar", false)) + .build(); + message.addData(new WxMaTemplateData("first", "恭喜你购买成功!", "#173177")) + .addData(new WxMaTemplateData("keyword1", "巧克力", "#173177")) + .addData(new WxMaTemplateData("keyword2", "39.8元", "#173177")) + .addData(new WxMaTemplateData("keyword3", "2014年9月22日", "#173177")) + .addData(new WxMaTemplateData("remark", "欢迎再次购买!", "#173177")); + + assertThat(message.toJson()).isEqualTo(new JsonParser().parse("{\n" + + " \"touser\":\"OPENID\",\n" + + " \"mp_template_msg\":{\n" + + " \"appid\":\"APPID\",\n" + + " \"template_id\":\"TEMPLATE_ID\",\n" + + " \"url\":\"http://weixin.qq.com/download\",\n" + + " \"miniprogram\":{\n" + + " \"appid\":\"xiaochengxuappid12345\",\n" + + " \"pagepath\":\"index?foo=bar\"\n" + + " },\n" + + " \"data\":{\n" + + " \"first\":{\n" + + " \"value\":\"恭喜你购买成功!\",\n" + + " \"color\":\"#173177\"\n" + + " },\n" + + " \"keyword1\":{\n" + + " \"value\":\"巧克力\",\n" + + " \"color\":\"#173177\"\n" + + " },\n" + + " \"keyword2\":{\n" + + " \"value\":\"39.8元\",\n" + + " \"color\":\"#173177\"\n" + + " },\n" + + " \"keyword3\":{\n" + + " \"value\":\"2014年9月22日\",\n" + + " \"color\":\"#173177\"\n" + + " },\n" + + " \"remark\":{\n" + + " \"value\":\"欢迎再次购买!\",\n" + + " \"color\":\"#173177\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}").getAsJsonObject().toString()); + } + + @Test + public void testSerialize_ma() { + WxMaUniformMessage message = WxMaUniformMessage.builder() + .isMpTemplateMsg(false) + .toUser("OPENID") + .page("page/page/index") + .templateId("TEMPLATE_ID") + .formId("FORMID") + .emphasisKeyword("keyword1.DATA") + .build(); + message.addData(new WxMaTemplateData("keyword1", "339208499")) + .addData(new WxMaTemplateData("keyword2", "2015年01月05日 12:30")) + .addData(new WxMaTemplateData("keyword3", "腾讯微信总部")) + .addData(new WxMaTemplateData("keyword4", "广州市海珠区新港中路397号")); + + assertThat(message.toJson()).isEqualTo(new JsonParser().parse("{\n" + + " \"touser\":\"OPENID\",\n" + + " \"weapp_template_msg\":{\n" + + " \"template_id\":\"TEMPLATE_ID\",\n" + + " \"page\":\"page/page/index\",\n" + + " \"form_id\":\"FORMID\",\n" + + " \"data\":{\n" + + " \"keyword1\":{\n" + + " \"value\":\"339208499\"\n" + + " },\n" + + " \"keyword2\":{\n" + + " \"value\":\"2015年01月05日 12:30\"\n" + + " },\n" + + " \"keyword3\":{\n" + + " \"value\":\"腾讯微信总部\"\n" + + " },\n" + + " \"keyword4\":{\n" + + " \"value\":\"广州市海珠区新港中路397号\"\n" + + " }\n" + + " },\n" + + " \"emphasis_keyword\":\"keyword1.DATA\"\n" + + " }\n" + + "}").getAsJsonObject().toString()); + } +} diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index fbffe94d..8441e4cd 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 3.1.0 + 3.2.0 weixin-java-mp Weixin Java Tools - MP diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java index 9545709a..1ad01eea 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java @@ -2,12 +2,16 @@ package me.chanjar.weixin.mp.api; import me.chanjar.weixin.common.bean.WxCardApiSignature; import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.card.WxMpCardLandingPageCreateRequest; +import me.chanjar.weixin.mp.bean.card.WxMpCardLandingPageCreateResult; +import me.chanjar.weixin.mp.bean.card.WxMpCardQrcodeCreateResult; import me.chanjar.weixin.mp.bean.result.WxMpCardResult; /** * 卡券相关接口 * - * @author YuJian(mgcnrx11@hotmail.com) on 01/11/2016 + * @author YuJian(mgcnrx11 @ hotmail.com) on 01/11/2016 + * @author yuanqixun 2018-08-29 */ public interface WxMpCardService { String CARD_GET = "https://api.weixin.qq.com/card/get"; @@ -16,6 +20,13 @@ public interface WxMpCardService { String CARD_CODE_GET = "https://api.weixin.qq.com/card/code/get"; String CARD_CODE_CONSUME = "https://api.weixin.qq.com/card/code/consume"; String CARD_CODE_MARK = "https://api.weixin.qq.com/card/code/mark"; + String CARD_TEST_WHITELIST = "https://api.weixin.qq.com/card/testwhitelist/set"; + String CARD_QRCODE_CREAET = "https://api.weixin.qq.com/card/qrcode/create"; + String CARD_LANDING_PAGE_CREAET = "https://api.weixin.qq.com/card/landingpage/create"; + /** + * 将用户的卡券设置为失效状态 + */ + String CARD_CODE_UNAVAILABLE = "https://api.weixin.qq.com/card/code/unavailable"; /** * 得到WxMpService @@ -122,4 +133,53 @@ public interface WxMpCardService { *
可由 com.google.gson.JsonParser#parse 等方法直接取JSON串中的某个字段。 */ String getCardDetail(String cardId) throws WxErrorException; + + /** + * 添加测试白名单 + * + * @param openid 用户的openid + * @return + */ + String addTestWhiteList(String openid) throws WxErrorException; + + /** + * 创建卡券二维码 + * + * @param cardId 卡券编号 + * @param outerStr 二维码标识 + * @return WxMpCardQrcodeCreateResult + */ + WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr) throws WxErrorException; + + /** + * 创建卡券二维码 + * + * @param cardId 卡券编号 + * @param outerStr 二维码标识 + * @param expiresIn 失效时间,单位秒,不填默认365天 + * @return WxMpCardQrcodeCreateResult + */ + WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn) throws WxErrorException; + + /** + * 创建卡券货架 + * + * @param createRequest 货架创建参数 + * @return + * @throws WxErrorException + */ + WxMpCardLandingPageCreateResult createLandingPage(WxMpCardLandingPageCreateRequest createRequest) throws WxErrorException; + + /** + * 将用户的卡券设置为失效状态 + * 详见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025272&anchor=9 + * + * @param cardId 卡券编号 + * @param code 用户会员卡号 + * @param reason 设置为失效的原因 + * @return + * @throws WxErrorException + */ + String unavailableCardCode(String cardId, String code, String reason) throws WxErrorException; + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java index 46a22fa8..eb15cd0f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java @@ -1,13 +1,15 @@ package me.chanjar.weixin.mp.api; -import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.ToStringUtils; -import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; - import java.io.File; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; + /** * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 * @@ -248,7 +250,7 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } @Override diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java index e5c27350..99dcaba9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java @@ -1,16 +1,21 @@ package me.chanjar.weixin.mp.api; +import java.io.File; +import java.util.Date; + import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; -import me.chanjar.weixin.mp.bean.kefu.result.*; - -import java.io.File; -import java.util.Date; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfMsgList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionGetResult; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionWaitCaseList; /** *
- * 客服接口 ,
+ * 客服接口.
  * 注意:命名采用kefu拼音的原因是:其英文CustomerService如果再加上Service后缀显得有点啰嗦,如果不加又显得表意不完整。
  * 
* @@ -30,7 +35,8 @@ public interface WxMpKefuService { String KFSESSION_GET_SESSION = "https://api.weixin.qq.com/customservice/kfsession/getsession?openid=%s"; String KFSESSION_GET_SESSION_LIST = "https://api.weixin.qq.com/customservice/kfsession/getsessionlist?kf_account=%s"; String KFSESSION_GET_WAIT_CASE = "https://api.weixin.qq.com/customservice/kfsession/getwaitcase"; - String MSGRECORD_GET_MSG_LIST = "https://api.weixin.qq.com/customservice/msgrecord/getmsglist"; + String MSG_RECORD_LIST = "https://api.weixin.qq.com/customservice/msgrecord/getmsglist"; + String CUSTOM_TYPING = "https://api.weixin.qq.com/cgi-bin/message/custom/typing"; /** *
@@ -38,6 +44,8 @@ public interface WxMpKefuService {
    * 详情请见: 发送客服消息
    * 接口url格式:https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
    * 
+ * + * @throws WxErrorException 异常 */ boolean sendKefuMessage(WxMpKefuMessage message) throws WxErrorException; @@ -49,6 +57,8 @@ public interface WxMpKefuService { * 详情请见:客服管理 * 接口url格式:https://api.weixin.qq.com/cgi-bin/customservice/getkflist?access_token=ACCESS_TOKEN *
+ * + * @throws WxErrorException 异常 */ WxMpKfList kfList() throws WxErrorException; @@ -58,6 +68,8 @@ public interface WxMpKefuService { * 详情请见:客服管理 * 接口url格式:https://api.weixin.qq.com/cgi-bin/customservice/getonlinekflist?access_token=ACCESS_TOKEN *
+ * + * @throws WxErrorException 异常 */ WxMpKfOnlineList kfOnlineList() throws WxErrorException; @@ -67,6 +79,8 @@ public interface WxMpKefuService { * 详情请见:客服管理 * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/add?access_token=ACCESS_TOKEN *
+ * + * @throws WxErrorException 异常 */ boolean kfAccountAdd(WxMpKfAccountRequest request) throws WxErrorException; @@ -85,6 +99,8 @@ public interface WxMpKefuService { * 详情请见:客服管理 * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/inviteworker?access_token=ACCESS_TOKEN *
+ * + * @throws WxErrorException 异常 */ boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErrorException; @@ -94,8 +110,10 @@ public interface WxMpKefuService { * 详情请见:客服管理 * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/uploadheadimg?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT *
+ * + * @throws WxErrorException 异常 */ - boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) throws WxErrorException; + boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) throws WxErrorException; /** *
@@ -103,6 +121,8 @@ public interface WxMpKefuService {
    * 详情请见:客服管理
    * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/del?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
    * 
+ * + * @throws WxErrorException 异常 */ boolean kfAccountDel(String kfAccount) throws WxErrorException; @@ -115,6 +135,8 @@ public interface WxMpKefuService { * 详情请见:客服会话控制接口 * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/create?access_token=ACCESS_TOKEN * + * + * @throws WxErrorException 异常 */ boolean kfSessionCreate(String openid, String kfAccount) throws WxErrorException; @@ -125,6 +147,8 @@ public interface WxMpKefuService { * 详情请见:客服会话控制接口 * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/close?access_token=ACCESS_TOKEN * + * + * @throws WxErrorException 异常 */ boolean kfSessionClose(String openid, String kfAccount) throws WxErrorException; @@ -135,6 +159,8 @@ public interface WxMpKefuService { * 详情请见:客服会话控制接口 * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getsession?access_token=ACCESS_TOKEN&openid=OPENID * + * + * @throws WxErrorException 异常 */ WxMpKfSessionGetResult kfSessionGet(String openid) throws WxErrorException; @@ -145,6 +171,8 @@ public interface WxMpKefuService { * 详情请见:客服会话控制 * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getsessionlist?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT * + * + * @throws WxErrorException 异常 */ WxMpKfSessionList kfSessionList(String kfAccount) throws WxErrorException; @@ -155,6 +183,8 @@ public interface WxMpKefuService { * 详情请见:客服会话控制 * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getwaitcase?access_token=ACCESS_TOKEN * + * + * @throws WxErrorException 异常 */ WxMpKfSessionWaitCaseList kfSessionGetWaitCase() throws WxErrorException; @@ -173,7 +203,7 @@ public interface WxMpKefuService { * @param msgId 消息id顺序从小到大,从1开始 * @param number 每次获取条数,最多10000条 * @return 聊天记录对象 - * @throws WxErrorException + * @throws WxErrorException 异常 */ WxMpKfMsgList kfMsgList(Date startTime, Date endTime, Long msgId, Integer number) throws WxErrorException; @@ -188,8 +218,27 @@ public interface WxMpKefuService { * @param startTime 起始时间 * @param endTime 结束时间 * @return 聊天记录对象 - * @throws WxErrorException + * @throws WxErrorException 异常 */ WxMpKfMsgList kfMsgList(Date startTime, Date endTime) throws WxErrorException; + /** + *
+   * 客服输入状态
+   * 开发者可通过调用“客服输入状态”接口,返回客服当前输入状态给用户。
+   * 此接口需要客服消息接口权限。
+   * 如果不满足发送客服消息的触发条件,则无法下发输入状态。
+   * 下发输入状态,需要客服之前30秒内跟用户有过消息交互。
+   * 在输入状态中(持续15s),不可重复下发输入态。
+   * 在输入状态中,如果向用户下发消息,会同时取消输入状态。
+   *
+   * 详情请见:客服输入状态
+   * 接口url格式:https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=ACCESS_TOKEN
+   * 
+ * + * @param openid 用户id + * @param command "Typing":对用户下发“正在输入"状态 "CancelTyping":取消对用户的”正在输入"状态 + * @throws WxErrorException 异常 + */ + boolean sendKfTypingState(String openid, String command) throws WxErrorException; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java index 50490dbb..6d762f1c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java @@ -1,12 +1,20 @@ package me.chanjar.weixin.mp.api; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; -import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.mp.bean.material.*; - import java.io.File; import java.io.InputStream; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import me.chanjar.weixin.mp.bean.material.WxMpMaterial; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialArticleUpdate; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialCountResult; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialFileBatchGetResult; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialNewsBatchGetResult; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; + /** *
  * Created by Binary Wang on 2016/7/21.
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java
index 9c022034..d9bbdfbc 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java
@@ -1,29 +1,57 @@
 package me.chanjar.weixin.mp.api;
 
 import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardActivatedMessage;
-import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateMessage;
-import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateResult;
-import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUserInfoResult;
+import me.chanjar.weixin.mp.bean.card.MemberCardActivateUserFormRequest;
+import me.chanjar.weixin.mp.bean.card.MemberCardActivateUserFormResult;
+import me.chanjar.weixin.mp.bean.card.WxMpCardCreateResult;
+import me.chanjar.weixin.mp.bean.membercard.*;
 
 /**
  * 会员卡相关接口
  *
- * @author YuJian(mgcnrx11@gmail.com)
+ * @author YuJian(mgcnrx11 @ gmail.com)
+ * @author yuanqixun
  * @version 2017/7/8
+ * @date 2018-08-30
  */
 public interface WxMpMemberCardService {
+  String MEMBER_CARD_CREAET = "https://api.weixin.qq.com/card/create";
+  String MEMBER_CARD_ACTIVATE = "https://api.weixin.qq.com/card/membercard/activate";
+  String MEMBER_CARD_USER_INFO_GET = "https://api.weixin.qq.com/card/membercard/userinfo/get";
+  String MEMBER_CARD_UPDATE_USER = "https://api.weixin.qq.com/card/membercard/updateuser";
+  /**
+   * 会员卡激活之微信开卡接口(wx_activate=true情况调用)
+   */
+  String MEMBER_CARD_ACTIVATEUSERFORM = "https://api.weixin.qq.com/card/membercard/activateuserform/set";
 
   /**
    * 得到WxMpService
    */
   WxMpService getWxMpService();
 
+  /**
+   * 会员卡创建接口
+   *
+   * @param createJson
+   * @return
+   * @throws WxErrorException
+   */
+  WxMpCardCreateResult createMemberCard(String createJson) throws WxErrorException;
+
+  /**
+   * 会员卡创建接口
+   *
+   * @param createMessageMessage
+   * @return WxMpCardCreateResult
+   * @throws WxErrorException
+   */
+  WxMpCardCreateResult createMemberCard(WxMpMemberCardCreateMessage createMessageMessage) throws WxErrorException;
+
   /**
    * 会员卡激活接口
    *
    * @param activatedMessage 激活所需参数
-   * @return 调用返回的JSON字符串。
+   * @return 返回json字符串
    * @throws WxErrorException 接口调用失败抛出的异常
    */
   String activateMemberCard(WxMpMemberCardActivatedMessage activatedMessage) throws WxErrorException;
@@ -32,7 +60,7 @@ public interface WxMpMemberCardService {
    * 拉取会员信息接口
    *
    * @param cardId 会员卡的CardId,微信分配
-   * @param code 领取会员的会员卡Code
+   * @param code   领取会员的会员卡Code
    * @return 会员信息的结果对象
    * @throws WxErrorException 接口调用失败抛出的异常
    */
@@ -40,7 +68,7 @@ public interface WxMpMemberCardService {
 
   /**
    * 当会员持卡消费后,支持开发者调用该接口更新会员信息。会员卡交易后的每次信息变更需通过该接口通知微信,便于后续消息通知及其他扩展功能。
-   *
+   * 

* 1.开发者可以同时传入add_bonus和bonus解决由于同步失败带来的幂等性问题。同时传入add_bonus和bonus时 * add_bonus作为积分变动消息中的变量值,而bonus作为卡面上的总积分额度显示。余额变动同理。 * 2.开发者可以传入is_notify_bonus控制特殊的积分对账变动不发送消息,余额变动同理。 @@ -50,4 +78,14 @@ public interface WxMpMemberCardService { * @throws WxErrorException 接口调用失败抛出的异常 */ WxMpMemberCardUpdateResult updateUserMemberCard(WxMpMemberCardUpdateMessage updateUserMessage) throws WxErrorException; + + /** + * 设置会员卡激活的字段(会员卡设置:wx_activate=true 时需要) + * + * @param userFormRequest + * @return + * @throws WxErrorException + */ + MemberCardActivateUserFormResult setActivateUserForm(MemberCardActivateUserFormRequest userFormRequest) throws WxErrorException; + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java index c3a75f64..bc1a0724 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java @@ -1,9 +1,6 @@ package me.chanjar.weixin.mp.api.impl; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonPrimitive; +import com.google.gson.*; import com.google.gson.reflect.TypeToken; import me.chanjar.weixin.common.bean.WxCardApiSignature; import me.chanjar.weixin.common.error.WxError; @@ -13,8 +10,12 @@ import me.chanjar.weixin.common.util.crypto.SHA1; import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; import me.chanjar.weixin.mp.api.WxMpCardService; import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.card.WxMpCardLandingPageCreateRequest; +import me.chanjar.weixin.mp.bean.card.WxMpCardLandingPageCreateResult; +import me.chanjar.weixin.mp.bean.card.WxMpCardQrcodeCreateResult; import me.chanjar.weixin.mp.bean.result.WxMpCardResult; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,6 +31,8 @@ public class WxMpCardServiceImpl implements WxMpCardService { private WxMpService wxMpService; + private static final Gson GSON = new Gson(); + public WxMpCardServiceImpl(WxMpService wxMpService) { this.wxMpService = wxMpService; } @@ -236,4 +239,90 @@ public class WxMpCardServiceImpl implements WxMpCardService { return responseContent; } + + /** + * 添加测试白名单 + * + * @param openid 用户的openid + * @return + */ + public String addTestWhiteList(String openid) throws WxErrorException { + JsonArray array = new JsonArray(); + array.add(openid); + JsonObject jsonObject = new JsonObject(); + jsonObject.add("openid", array); + String respone = this.wxMpService.post(CARD_TEST_WHITELIST, GSON.toJson(jsonObject)); + return respone; + } + + /** + * 创建卡券二维码 + * + * @param cardId + * @param outerStr + * @return + */ + public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr) throws WxErrorException { + return createQrcodeCard(cardId, outerStr, 0); + } + + /** + * 创建卡券二维码 + * + * @param cardId 卡券编号 + * @param outerStr 二维码标识 + * @param expiresIn 失效时间,单位秒,不填默认365天 + * @return + * @throws WxErrorException + */ + public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn) throws WxErrorException { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("action_name", "QR_CARD"); + if (expiresIn > 0) { + jsonObject.addProperty("expire_seconds", expiresIn); + } + JsonObject actionInfoJson = new JsonObject(); + JsonObject cardJson = new JsonObject(); + cardJson.addProperty("card_id", cardId); + cardJson.addProperty("outer_str", outerStr); + actionInfoJson.add("card", cardJson); + jsonObject.add("action_info", actionInfoJson); + String response = this.wxMpService.post(CARD_QRCODE_CREAET, GSON.toJson(jsonObject)); + return WxMpCardQrcodeCreateResult.fromJson(response); + } + + /** + * 创建卡券货架接口 + * + * @param request + * @return + * @throws WxErrorException + */ + @Override + public WxMpCardLandingPageCreateResult createLandingPage(WxMpCardLandingPageCreateRequest request) throws WxErrorException { + String response = this.wxMpService.post(CARD_LANDING_PAGE_CREAET, GSON.toJson(request)); + return WxMpCardLandingPageCreateResult.fromJson(response); + } + + /** + * 将用户的卡券设置为失效状态 + * 详见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025272&anchor=9 + * + * @param cardId 卡券编号 + * @param code 用户会员卡号 + * @param reason 设置为失效的原因 + * @return + * @throws WxErrorException + */ + @Override + public String unavailableCardCode(String cardId, String code, String reason) throws WxErrorException { + if (StringUtils.isAnyBlank(cardId, code, reason)) + throw new WxErrorException(WxError.builder().errorCode(41012).errorMsg("参数不完整").build()); + JsonObject jsonRequest = new JsonObject(); + jsonRequest.addProperty("card_id", cardId); + jsonRequest.addProperty("code", code); + jsonRequest.addProperty("reason", reason); + String response = this.wxMpService.post(CARD_CODE_UNAVAILABLE, GSON.toJson(jsonRequest)); + return response; + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java index 604ce832..7707c567 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java @@ -1,8 +1,14 @@ package me.chanjar.weixin.mp.api.impl; +import java.io.File; +import java.util.Date; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.google.gson.JsonObject; -import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.mp.api.WxMpKefuService; @@ -10,12 +16,12 @@ import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfSessionRequest; -import me.chanjar.weixin.mp.bean.kefu.result.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.util.Date; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfMsgList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionGetResult; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionWaitCaseList; /** * @author Binary Wang @@ -120,12 +126,12 @@ public class WxMpKefuServiceImpl implements WxMpKefuService { } JsonObject param = new JsonObject(); - param.addProperty("starttime", startTime.getTime() / 1000); //starttime 起始时间,unix时间戳 - param.addProperty("endtime", endTime.getTime() / 1000); //endtime 结束时间,unix时间戳,每次查询时段不能超过24小时 - param.addProperty("msgid", msgId); //msgid 消息id顺序从小到大,从1开始 - param.addProperty("number", number); //number 每次获取条数,最多10000条 + param.addProperty("starttime", startTime.getTime() / 1000); + param.addProperty("endtime", endTime.getTime() / 1000); + param.addProperty("msgid", msgId); + param.addProperty("number", number); - String responseContent = this.wxMpService.post(MSGRECORD_GET_MSG_LIST, param.toString()); + String responseContent = this.wxMpService.post(MSG_RECORD_LIST, param.toString()); return WxMpKfMsgList.fromJson(responseContent); } @@ -149,4 +155,13 @@ public class WxMpKefuServiceImpl implements WxMpKefuService { return result; } + @Override + public boolean sendKfTypingState(String openid, String command) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("touser", openid); + params.addProperty("command", command); + String responseContent = this.wxMpService.post(CUSTOM_TYPING, params.toString()); + return responseContent != null; + } + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java index 5c539b5b..7929aced 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java @@ -1,9 +1,16 @@ package me.chanjar.weixin.mp.api.impl; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.api.WxConsts; -import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor; @@ -11,17 +18,22 @@ import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.api.WxMpMaterialService; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.material.*; -import me.chanjar.weixin.mp.util.requestexecuter.material.*; -import me.chanjar.weixin.mp.util.requestexecuter.media.MediaImgUploadRequestExecutor; +import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import me.chanjar.weixin.mp.bean.material.WxMpMaterial; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialArticleUpdate; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialCountResult; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialFileBatchGetResult; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialNewsBatchGetResult; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; +import me.chanjar.weixin.mp.util.requestexecuter.material.MaterialDeleteRequestExecutor; +import me.chanjar.weixin.mp.util.requestexecuter.material.MaterialNewsInfoRequestExecutor; +import me.chanjar.weixin.mp.util.requestexecuter.material.MaterialUploadRequestExecutor; +import me.chanjar.weixin.mp.util.requestexecuter.material.MaterialVideoInfoRequestExecutor; +import me.chanjar.weixin.mp.util.requestexecuter.material.MaterialVoiceAndImageDownloadRequestExecutor; +import me.chanjar.weixin.mp.util.requestexecuter.media.MediaImgUploadRequestExecutor; /** * Created by Binary Wang on 2016/7/21. diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java index 8eb09cc1..3c4d0ab5 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java @@ -6,30 +6,29 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.api.WxMpMemberCardService; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardActivatedMessage; -import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateMessage; -import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateResult; -import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUserInfoResult; +import me.chanjar.weixin.mp.bean.card.*; +import me.chanjar.weixin.mp.bean.card.enums.BusinessServiceType; +import me.chanjar.weixin.mp.bean.card.enums.CardColor; +import me.chanjar.weixin.mp.bean.card.enums.DateInfoType; +import me.chanjar.weixin.mp.bean.membercard.*; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 会员卡相关接口的实现类 * - * @author YuJian(mgcnrx11@gmail.com) + * @author YuJian(mgcnrx11 @ gmail.com) * @version 2017/7/8 */ public class WxMpMemberCardServiceImpl implements WxMpMemberCardService { private final Logger log = LoggerFactory.getLogger(WxMpMemberCardServiceImpl.class); - private static final String MEMBER_CARD_ACTIVATE = "https://api.weixin.qq.com/card/membercard/activate"; - private static final String MEMBER_CARD_USER_INFO_GET = "https://api.weixin.qq.com/card/membercard/userinfo/get"; - private static final String MEMBER_CARD_UPDATE_USER = "https://api.weixin.qq.com/card/membercard/updateuser"; - private WxMpService wxMpService; private static final Gson GSON = new Gson(); @@ -46,11 +45,176 @@ public class WxMpMemberCardServiceImpl implements WxMpMemberCardService { return this.wxMpService; } + /** + * 会员卡创建接口 + * + * @param createJson 创建json + * @return 调用返回的JSON字符串。 + * @throws WxErrorException 接口调用失败抛出的异常 + */ + @Override + public WxMpCardCreateResult createMemberCard(String createJson) throws WxErrorException { + WxMpMemberCardCreateMessage createMessage = WxGsonBuilder.create().fromJson(createJson, WxMpMemberCardCreateMessage.class); + return createMemberCard(createMessage); + } + + /** + * 会员卡创建接口 + * + * @param createMessageMessage 创建所需参数 + * @return WxMpCardCreateResult。 + * @throws WxErrorException 接口调用失败抛出的异常 + */ + @Override + public WxMpCardCreateResult createMemberCard(WxMpMemberCardCreateMessage createMessageMessage) throws WxErrorException { + //校验请求对象合法性 + WxMpCardCreateResult validResult = validCheck(createMessageMessage); + if (!validResult.isSuccess()) + return validResult; + String response = this.wxMpService.post(MEMBER_CARD_CREAET, GSON.toJson(createMessageMessage)); + return WxMpCardCreateResult.fromJson(response); + } + + private WxMpCardCreateResult validCheck(WxMpMemberCardCreateMessage createMessageMessage) throws WxErrorException { + if (createMessageMessage == null) { + return WxMpCardCreateResult.failure("对象不能为空"); + } + MemberCardCreateRequest cardCreateRequest = createMessageMessage.getCardCreateRequest(); + if (createMessageMessage == null) { + return WxMpCardCreateResult.failure("会员卡对象不能为空"); + } + String cardType = cardCreateRequest.getCardType(); + if (!StringUtils.equals(cardType, "MEMBER_CARD")) { + return WxMpCardCreateResult.failure("卡券类型必须等于MEMBER_CARD"); + } + MemberCard memberCard = cardCreateRequest.getMemberCard(); + + if (StringUtils.isEmpty(memberCard.getPrerogative())) { + return WxMpCardCreateResult.failure("会员卡特权说明不能为空:prerogative"); + } + //卡片激活规则 + if (!memberCard.isAutoActivate() && !memberCard.isWxActivate() && StringUtils.isEmpty(memberCard.getActivateUrl())) { + return WxMpCardCreateResult.failure("会员卡激活方式为接口激活,activate_url不能为空"); + } + + //积分支持 +// if(memberCard.isSupplyBonus() && StringUtils.isEmpty(memberCard.getBonusUrl())){ +// return WxMpCardCreateResult.failure("会员卡支持积分,bonus_url不能为空"); +// } +// if(memberCard.isSupplyBonus() && memberCard.getBonusRule() == null){ +// return WxMpCardCreateResult.failure("会员卡支持积分,bonus_rule不能为空"); +// } + BaseInfo baseInfo = memberCard.getBaseInfo(); + if (baseInfo == null) { + return WxMpCardCreateResult.failure("会员卡基本信息对象base_info不能为空"); + } + + if (StringUtils.isBlank(baseInfo.getLogoUrl())) { + return WxMpCardCreateResult.failure("会员卡基本信息的商户logo:logo_url不能为空"); + } + + if (StringUtils.isBlank(baseInfo.getCodeType())) { + return WxMpCardCreateResult.failure("会员卡基本信息的条码类型:code_type不能为空"); + } + + if (StringUtils.isBlank(baseInfo.getBrandName())) { + return WxMpCardCreateResult.failure("会员卡基本信息的商户名字:brand_name不能为空"); + } + + if (StringUtils.length(baseInfo.getBrandName()) > 12) { + return WxMpCardCreateResult.failure("会员卡基本信息的商户名字:brand_name长度不能大于12个汉字"); + } + + if (StringUtils.isBlank(baseInfo.getTitle())) { + return WxMpCardCreateResult.failure("会员卡基本信息的卡券名称:title不能为空"); + } + + if (StringUtils.length(baseInfo.getTitle()) > 9) { + return WxMpCardCreateResult.failure("会员卡基本信息的卡券名称:title长度不能大于9个汉字"); + } + + if (StringUtils.isBlank(baseInfo.getColor())) { + return WxMpCardCreateResult.failure("会员卡基本信息的卡颜色:color不能为空"); + } + + CardColor cardColor = null; + try { + cardColor = CardColor.valueOf(baseInfo.getColor()); + } catch (IllegalArgumentException ex) { + + } + if (cardColor == null) { + return WxMpCardCreateResult.failure("会员卡基本信息的卡颜色:" + baseInfo.getColor() + "不支持"); + } + + if (StringUtils.isBlank(baseInfo.getNotice())) { + return WxMpCardCreateResult.failure("会员卡基本信息的使用提醒:notice不能为空"); + } + + if (StringUtils.isBlank(baseInfo.getDescription())) { + return WxMpCardCreateResult.failure("会员卡基本信息的使用说明:description不能为空"); + } + + if (baseInfo.getSku() == null) { + return WxMpCardCreateResult.failure("会员卡基本信息的商品信息:sku不能为空"); + } + + DateInfo dateInfo = baseInfo.getDateInfo(); + if (dateInfo == null) { + return WxMpCardCreateResult.failure("会员卡基本信息的使用日期:date_info不能为空"); + } + + DateInfoType dateInfoType = null; + try { + dateInfoType = DateInfoType.valueOf(dateInfo.getType()); + } catch (IllegalArgumentException ex) { + + } + + if (dateInfoType == null) { + return WxMpCardCreateResult.failure("会员卡基本信息的使用日期类型:" + dateInfo.getType() + "不合法"); + } + + //固定时长 + if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TERM && (dateInfo.getFixedTerm() == null || dateInfo.getFixedBeginTerm() == null)) { + return WxMpCardCreateResult.failure("会员卡基本信息的使用日期为:" + dateInfoType.getDescription() + ",fixedTerm和fixedBeginTerm不能为空"); + } + + //固定期限 + if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TIME_RANGE && (dateInfo.getBeginTimestamp() == null || dateInfo.getEndTimestamp() == null)) { + return WxMpCardCreateResult.failure("会员卡基本信息的使用日期为:" + dateInfoType.getDescription() + ",beginTimestamp 和 endTimestamp 不能为空"); + } + if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TIME_RANGE && (dateInfo.getBeginTimestamp() < System.currentTimeMillis() || dateInfo.getEndTimestamp() < System.currentTimeMillis() || dateInfo.getBeginTimestamp() > dateInfo.getEndTimestamp())) { + return WxMpCardCreateResult.failure("会员卡基本信息的使用日期为:" + dateInfoType.getDescription() + ",beginTimestamp和endTimestamp的值不合法,请检查"); + } + + if (!baseInfo.isUseAllLocations() && StringUtils.isBlank(baseInfo.getLocationIdList())) { + return WxMpCardCreateResult.failure("会员卡基本信息的门店使用范围选择指定门店,门店列表:locationIdList不能为空"); + } + + //校验高级信息 + AdvancedInfo advancedInfo = memberCard.getAdvancedInfo(); + if (advancedInfo != null) { + if (advancedInfo.getBusinessServiceList() != null) { + for (String bs : advancedInfo.getBusinessServiceList()) { + BusinessServiceType businessServiceType = null; + try { + businessServiceType = BusinessServiceType.valueOf(bs); + } catch (IllegalArgumentException ex) { + return WxMpCardCreateResult.failure("会员卡高级信息的商户服务:" + bs + " 不合法"); + } + } + } + } + + return WxMpCardCreateResult.success(); + } + /** * 会员卡激活接口 * * @param activatedMessage 激活所需参数 - * @return 调用返回的JSON字符串。 + * @return WxMpCardCreateResult。 * @throws WxErrorException 接口调用失败抛出的异常 */ @Override @@ -70,9 +234,10 @@ public class WxMpMemberCardServiceImpl implements WxMpMemberCardService { public WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) throws WxErrorException { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("card_id", cardId); - jsonObject.addProperty("code",code); + jsonObject.addProperty("code", code); String responseContent = this.getWxMpService().post(MEMBER_CARD_USER_INFO_GET, jsonObject.toString()); + log.debug("{}",responseContent); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, new TypeToken() { @@ -81,7 +246,7 @@ public class WxMpMemberCardServiceImpl implements WxMpMemberCardService { /** * 当会员持卡消费后,支持开发者调用该接口更新会员信息。会员卡交易后的每次信息变更需通过该接口通知微信,便于后续消息通知及其他扩展功能。 - * + *

* 1.开发者可以同时传入add_bonus和bonus解决由于同步失败带来的幂等性问题。同时传入add_bonus和bonus时 * add_bonus作为积分变动消息中的变量值,而bonus作为卡面上的总积分额度显示。余额变动同理。 * 2.开发者可以传入is_notify_bonus控制特殊的积分对账变动不发送消息,余额变动同理。 @@ -101,4 +266,18 @@ public class WxMpMemberCardServiceImpl implements WxMpMemberCardService { new TypeToken() { }.getType()); } + + /** + * 设置会员卡激活的字段(会员卡设置:wx_activate=true 时需要) + * + * @param userFormRequest + * @return + * @throws WxErrorException + */ + @Override + public MemberCardActivateUserFormResult setActivateUserForm(MemberCardActivateUserFormRequest userFormRequest) throws WxErrorException { + String responseContent = this.getWxMpService().post(MEMBER_CARD_ACTIVATEUSERFORM, GSON.toJson(userFormRequest)); + return MemberCardActivateUserFormResult.fromJson(responseContent); + } + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCard.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCard.java index 0fcb9185..622dca9e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCard.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCard.java @@ -1,11 +1,13 @@ package me.chanjar.weixin.mp.bean; -import lombok.Data; -import me.chanjar.weixin.common.util.ToStringUtils; - import java.io.Serializable; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import lombok.Data; + /** * 微信卡券 * @@ -28,6 +30,6 @@ public class WxMpCard implements Serializable{ @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java index b2ef87b1..5dd8c2ad 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java @@ -1,15 +1,17 @@ package me.chanjar.weixin.mp.bean; -import lombok.Data; -import me.chanjar.weixin.common.util.ToStringUtils; -import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; - import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + /** - * 群发时用到的图文消息素材 + * 群发时用到的图文消息素材. * * @author chanjarster */ @@ -33,12 +35,12 @@ public class WxMpMassNews implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } /** *

-   * 群发图文消息article
+   * 群发图文消息article.
    * 1. thumbMediaId  (必填) 图文消息缩略图的media_id,可以在基础支持-上传多媒体文件接口中获得
    * 2. author          图文消息的作者
    * 3. title           (必填) 图文消息的标题
@@ -53,37 +55,37 @@ public class WxMpMassNews implements Serializable {
   @Data
   public static class WxMpMassNewsArticle {
     /**
-     * (必填) 图文消息缩略图的media_id,可以在基础支持-上传多媒体文件接口中获得
+     * (必填) 图文消息缩略图的media_id,可以在基础支持-上传多媒体文件接口中获得.
      */
     private String thumbMediaId;
     /**
-     * 图文消息的作者
+     * 图文消息的作者.
      */
     private String author;
     /**
-     * (必填) 图文消息的标题
+     * (必填) 图文消息的标题.
      */
     private String title;
     /**
-     * 在图文消息页面点击“阅读原文”后的页面链接
+     * 在图文消息页面点击“阅读原文”后的页面链接.
      */
     private String contentSourceUrl;
     /**
-     * (必填) 图文消息页面的内容,支持HTML标签
+     * (必填) 图文消息页面的内容,支持HTML标签.
      */
     private String content;
     /**
-     * 图文消息的描述
+     * 图文消息的描述.
      */
     private String digest;
     /**
-     * 是否显示封面,true为显示,false为不显示
+     * 是否显示封面,true为显示,false为不显示.
      */
     private boolean showCoverPic;
 
     @Override
     public String toString() {
-      return ToStringUtils.toSimpleString(this);
+      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
     }
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Abstract.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Abstract.java
new file mode 100644
index 00000000..985cdb0a
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Abstract.java
@@ -0,0 +1,33 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+/**
+ * 封面摘要
+ * author:yuanqixun
+ * date:2018-08-25 00:35
+ */
+@Data
+public class Abstract implements Serializable {
+
+  /**
+   * 摘要
+   */
+  @SerializedName("abstract")
+  private String abstractInfo;
+
+  /**
+   * 封面图片列表,仅支持填入一 个封面图片链接, 上传图片接口 上传获取图片获得链接,填写 非CDN链接会报错,并在此填入。 建议图片尺寸像素850*350
+   */
+  @SerializedName("icon_url_list")
+  private String iconUrlList;
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/AdvancedInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/AdvancedInfo.java
new file mode 100644
index 00000000..73fd0135
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/AdvancedInfo.java
@@ -0,0 +1,76 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.mp.bean.card.enums.BusinessServiceType;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+//子对象列表
+
+/**
+ * 微信会员卡高级字段信息
+ * author:yuanqixun
+ * date:2018-08-25 00:36
+ */
+@Data
+public class AdvancedInfo implements Serializable {
+
+//    public AdvancedInfo(){
+//        useCondition = new UseCondition();
+//        abstractInfo = new Abstract();
+//        textImageList = new ArrayList<>();
+//        timeLimit = new TimeLimit();
+//    }
+
+  /**
+   * 使用门槛(条件),若不填写使用条件则在券面拼写 :无最低消费限制,全场通用,不限品类;并在使用说明显示: 可与其他优惠共享
+   */
+  @SerializedName("use_condition")
+  private UseCondition useCondition;
+
+  /**
+   * 封面摘要
+   */
+  @SerializedName("abstract")
+  private Abstract abstractInfo;
+
+  /**
+   * 图文列表,显示在详情内页 ,优惠券券开发者须至少传入 一组图文列表
+   */
+  @SerializedName("text_image_list")
+  private List textImageList;
+
+  /**
+   * 商家服务类型,数组类型:BIZ_SERVICE_DELIVER 外卖服务; BIZ_SERVICE_FREE_PARK 停车位; BIZ_SERVICE_WITH_PET 可带宠物; BIZ_SERVICE_FREE_WIFI 免费wifi, 可多选
+   */
+  @SerializedName("business_service")
+  private List businessServiceList;
+
+  /**
+   * 使用时段限制
+   */
+  @SerializedName("time_limit")
+  private TimeLimit timeLimit;
+
+  /**
+   * 是否可以分享朋友
+   */
+  @SerializedName("share_friends")
+  private Boolean shareFriends;
+
+  public void addBusinessService(BusinessServiceType businessServiceType) {
+    if (businessServiceType != null) {
+      if (businessServiceList == null)
+        businessServiceList = new ArrayList();
+      businessServiceList.add(businessServiceType.name());
+    }
+  }
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BaseInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BaseInfo.java
new file mode 100644
index 00000000..bdd0b359
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BaseInfo.java
@@ -0,0 +1,196 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+//子对象列表
+
+/**
+ * 微信会员卡基本信息
+ * author:yuanqixun
+ * date:2018-08-25 00:36
+ */
+@Data
+public class BaseInfo implements Serializable {
+
+  /**
+   * 卡券的商户logo,建议像素为300*300。
+   */
+  @SerializedName("logo_url")
+  private String logoUrl;
+
+  /**
+   * Code展示类型,"CODE_TYPE_TEXT" 文本 "CODE_TYPE_BARCODE" 一维码 "CODE_TYPE_QRCODE" 二维码 "CODE_TYPE_ONLY_QRCODE" 仅显示二维码 "CODE_TYPE_ONLY_BARCODE" 仅显示一维码 "CODE_TYPE_NONE" 不显示任何码型
+   */
+  @SerializedName("code_type")
+  private String codeType = "CODE_TYPE_QRCODE";
+
+  /**
+   * 支付功能结构体,swipe_card结构
+   */
+  @SerializedName("pay_info")
+  private PayInfo payInfo;
+
+  /**
+   * 是否设置该会员卡中部的按钮同时支持微信支付刷卡和会员卡二维码
+   */
+  @SerializedName("is_pay_and_qrcode")
+  private boolean isPayAndQrcode;
+
+  /**
+   * 商户名字,字数上限为12个汉字
+   */
+  @SerializedName("brand_name")
+  private String brandName;
+
+  /**
+   * 卡券名,字数上限为9个汉字 (建议涵盖卡券属性、服务及金额)。
+   */
+  @SerializedName("title")
+  private String title;
+
+  /**
+   * 券颜色,按色彩规范标注填写Color010-Color100
+   */
+  @SerializedName("color")
+  private String color;
+
+  /**
+   * 卡券使用提醒,字数上限为16个汉字
+   */
+  @SerializedName("notice")
+  private String notice;
+
+  /**
+   * 卡券使用说明,字数上限为1024个汉字。
+   */
+  @SerializedName("description")
+  private String description;
+
+  /**
+   * 商品信息
+   */
+  @SerializedName("sku")
+  private Sku sku;
+
+  /**
+   * 使用日期,有效期的信息。
+   */
+  @SerializedName("date_info")
+  private DateInfo dateInfo;
+
+  /**
+   * 是否自定义Code码,填写true或false,默认为false 通常自有优惠码系统的开发者选择自定义Code码,详情见 是否自定义code
+   */
+  @SerializedName("use_custom_code")
+  private boolean useCustomCode;
+
+  /**
+   * 是否指定用户领取,填写true或false。默认为false
+   */
+  @SerializedName("bind_openid")
+  private boolean bindOpenid;
+
+  /**
+   * 客服电话
+   */
+  @SerializedName("service_phone")
+  private String servicePhone;
+
+  /**
+   * 门店位置ID,调用 POI门店管理接口 获取门店位置ID。
+   */
+  @SerializedName("location_id_list")
+  private String locationIdList;
+
+  /**
+   * 会员卡是否支持全部门店,填写后商户门店更新时会自动同步至卡券
+   */
+  @SerializedName("use_all_locations")
+  private boolean useAllLocations = true;
+
+  /**
+   * 卡券中部居中的按钮,仅在卡券激活后且可用状态 时显示
+   */
+  @SerializedName("center_title")
+  private String centerTitle;
+
+  /**
+   * 显示在入口下方的提示语,仅在卡券激活后且可用状态时显示
+   */
+  @SerializedName("center_sub_title")
+  private String centerSubTitle;
+
+  /**
+   * 顶部居中的url,仅在卡券激活后且可用状态时显示
+   */
+  @SerializedName("center_url")
+  private String centerUrl;
+
+  /**
+   * 自定义跳转外链的入口名字
+   */
+  @SerializedName("custom_url_name")
+  private String customUrlName;
+
+  /**
+   * 自定义跳转的URL
+   */
+  @SerializedName("custom_url")
+  private String customUrl;
+
+  /**
+   * 显示在入口右侧的提示语
+   */
+  @SerializedName("custom_url_sub_title")
+  private String customUrlSubTitle;
+
+  /**
+   * 营销场景的自定义入口名称
+   */
+  @SerializedName("promotion_url_name")
+  private String promotionUrlName;
+
+  /**
+   * 入口跳转外链的地址链接
+   */
+  @SerializedName("promotion_url")
+  private String promotionUrl;
+
+  /**
+   * 显示在营销入口右侧的提示语
+   */
+  @SerializedName("promotion_url_sub_title")
+  private String promotionUrlSubTitle;
+
+  /**
+   * 每人可领券的数量限制,建议会员卡每人限领一张
+   */
+  @SerializedName("get_limit")
+  private Integer getLimit = 1;
+
+  /**
+   * 卡券领取页面是否可分享,默认为true
+   */
+  @SerializedName("can_share")
+  private boolean canShare;
+
+  /**
+   * 卡券是否可转赠,默认为true
+   */
+  @SerializedName("can_give_friend")
+  private boolean canGiveFriend;
+
+  /**
+   * 用户点击进入会员卡时推送事件,填写true为用户点击进入会员卡时推送事件,默认为false。详情见 进入会员卡事件推送
+   */
+  @SerializedName("need_push_on_view")
+  private boolean needPushOnView;
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BonusRule.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BonusRule.java
new file mode 100644
index 00000000..9b12d597
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BonusRule.java
@@ -0,0 +1,69 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+/**
+ * 积分规则
+ * author:yuanqixun
+ * date:2018-08-25 00:33
+ */
+@Data
+public class BonusRule implements Serializable {
+
+  /**
+   * 消费金额,以分为单位。
+   */
+  @SerializedName("cost_money_unit")
+  private Integer costMoneyUnit;
+
+  /**
+   * 对应增加的积分
+   */
+  @SerializedName("increase_bonus")
+  private Integer increaseBonus;
+
+  /**
+   * 用户单次可获取的积分上限
+   */
+  @SerializedName("max_increase_bonus")
+  private Integer maxIncreaseBonus;
+
+  /**
+   * 初始设置积分
+   */
+  @SerializedName("init_increase_bonus")
+  private Integer initIncreaseBonus;
+
+  /**
+   * 每使用积分
+   */
+  @SerializedName("cost_bonus_unit")
+  private Integer costBonusUnit;
+
+  /**
+   * 抵扣xx元,这里以分为单位)
+   */
+  @SerializedName("reduce_money")
+  private Integer reduceMoney;
+
+  /**
+   * 抵扣条件,满xx元(这里以分为单位)可用。
+   */
+  @SerializedName("least_moneyto_use_bonus")
+  private Integer leastMoneytoUseBonus;
+
+  /**
+   * 抵扣条件,单笔最多使用xx积分。
+   */
+  @SerializedName("max_reduce_bonus")
+  private Integer maxReduceBonus;
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CustomCell1.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CustomCell1.java
new file mode 100644
index 00000000..bfacd079
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CustomCell1.java
@@ -0,0 +1,39 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+/**
+ * 自定义会员信息类目
+ * author:yuanqixun
+ * date:2018-08-25 00:34
+ */
+@Data
+public class CustomCell1 implements Serializable {
+
+  /**
+   * 入口名称
+   */
+  @SerializedName("name")
+  private String name;
+
+  /**
+   * 入口右侧提示语,6个汉字内。
+   */
+  @SerializedName("tips")
+  private String tips;
+
+  /**
+   * 入口跳转链接。
+   */
+  @SerializedName("url")
+  private String url;
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CustomField.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CustomField.java
new file mode 100644
index 00000000..da7df64b
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CustomField.java
@@ -0,0 +1,43 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+/**
+ * 自定义会员信息类目
+ * author:yuanqixun
+ * date:2018-08-25 00:34
+ */
+@Data
+public class CustomField implements Serializable {
+
+  /**
+   * 半自定义名称,当开发者变更这类类目信息的value值时 可以选择触发系统模板消息通知用户。 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 次数
+   */
+  @SerializedName("name_type")
+  private String nameType;
+
+  /**
+   * 自定义名称,当开发者变更这类类目信息的value值时 不会触发系统模板消息通知用户
+   */
+  @SerializedName("name")
+  private String name;
+
+  /**
+   * 点击类目跳转外链url
+   */
+  @SerializedName("url")
+  private String url;
+
+  public String getNameType() {
+    return nameType;
+  }
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/DateInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/DateInfo.java
new file mode 100644
index 00000000..a4296650
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/DateInfo.java
@@ -0,0 +1,51 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+/**
+ * 使用日期,有效期的信息
+ * author:yuanqixun
+ * date:2018-08-25 00:31
+ */
+@Data
+public class DateInfo implements Serializable {
+
+  /**
+   * 使用时间的类型,支持固定时长有效类型 固定日期有效类型 永久有效类型:DATE_TYPE_FIX_TERM_RANGE、DATE_TYPE_FIX_TERM 、DATE_TYPE_PERMANENT
+   */
+  @SerializedName("type")
+  private String type = "DATE_TYPE_PERMANENT";
+
+  /**
+   * 起用时间,type为DATE_TYPE_FIX_TIME_RANGE时专用, 表示起用时间。从1970年1月1日00:00:00至起用时间的秒数 ( 东八区时间,UTC+8,单位为秒 )
+   */
+  @SerializedName("begin_timestamp")
+  private Long beginTimestamp;
+
+  /**
+   * 结束时间,type为DATE_TYPE_FIX_TERM_RANGE时专用,表示结束时间 ( 东八区时间,UTC+8,单位为秒 )
+   */
+  @SerializedName("end_timestamp")
+  private Long endTimestamp;
+
+  /**
+   * 自领取后多少天内有效,type为DATE_TYPE_FIX_TERM时专用,表示自领取后多少天内有效,领取后当天有效填写0(单位为天)
+   */
+  @SerializedName("fixed_term")
+  private Integer fixedTerm;
+
+  /**
+   * 自领取后多少天开始生效,type为DATE_TYPE_FIX_TERM时专用,表示自领取后多少天开始生效。(单位为天)
+   */
+  @SerializedName("fixed_begin_term")
+  private Integer fixedBeginTerm;
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCard.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCard.java
new file mode 100644
index 00000000..48e28eff
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCard.java
@@ -0,0 +1,152 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+@Data
+public final class MemberCard implements Serializable {
+
+  /**
+   * 会员卡背景图
+   */
+  @SerializedName("background_pic_url")
+  private String backgroundPicUrl;
+
+  /**
+   * 基本信息
+   */
+  @SerializedName("base_info")
+  private BaseInfo baseInfo;
+
+  /**
+   * 特权说明
+   */
+  @SerializedName("prerogative")
+  private String prerogative;
+
+  /**
+   * 自动激活
+   */
+  @SerializedName("auto_activate")
+  private boolean autoActivate;
+
+  /**
+   * 是否一键开卡
+   */
+  @SerializedName("wx_activate")
+  private boolean wxActivate;
+
+  /**
+   * 显示积分
+   */
+  @SerializedName("supply_bonus")
+  private boolean supplyBonus;
+
+  /**
+   * 查看积分外链,设置跳转外链查看积分详情。仅适用于积分无法通过激活接口同步的情况下使用该字段。
+   */
+  @SerializedName("bonus_url")
+  private String bonusUrl;
+
+  /**
+   * 支持储值
+   */
+  @SerializedName("supply_balance")
+  private boolean supplyBalance;
+
+  /**
+   * 余额外链,仅适用于余额无法通过激活接口同步的情况下使用该字段。
+   */
+  @SerializedName("balance_url")
+  private String balanceUrl;
+
+  /**
+   * 自定义会员类目1,会员卡激活后显示
+   */
+  @SerializedName("custom_field1")
+  private CustomField customField1;
+
+  /**
+   * 自定义会员类目2
+   */
+  @SerializedName("custom_field2")
+  private CustomField customField2;
+
+  /**
+   * 自定义会员类目3
+   */
+  @SerializedName("custom_field3")
+  private CustomField customField3;
+
+  /**
+   * 积分清零规则
+   */
+  @SerializedName("bonus_cleared")
+  private String bonusCleared;
+
+  /**
+   * 积分规则
+   */
+  @SerializedName("bonus_rules")
+  private String bonusRules;
+
+  /**
+   * 储值规则
+   */
+  @SerializedName("balance_rules")
+  private String balanceRules;
+
+  /**
+   * 激活会员卡的url
+   */
+  @SerializedName("activate_url")
+  private String activateUrl;
+
+  /**
+   * 激活会原卡url对应的小程序user_name,仅可跳转该公众号绑定的小程序
+   */
+  @SerializedName("activate_app_brand_user_name")
+  private String activateAppBrandUserName;
+
+  /**
+   * 激活会原卡url对应的小程序path
+   */
+  @SerializedName("activate_app_brand_pass")
+  private String activateAppBrandPass;
+
+  /**
+   * 自定义会员信息类目,会员卡激活后显示。
+   */
+  @SerializedName("custom_cell1")
+  private CustomCell1 customCell1;
+
+  /**
+   * 积分规则,JSON结构积分规则 。
+   */
+  @SerializedName("bonus_rule")
+  private BonusRule bonusRule;
+
+  /**
+   * 折扣,该会员卡享受的折扣优惠,填10就是九折。
+   */
+  private Integer discount;
+
+  /**
+   * 创建优惠券特有的高级字段
+   */
+  @SerializedName("advanced_info")
+  private AdvancedInfo advancedInfo;
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+
+  public static MemberCard fromJson(String json) {
+    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, MemberCard.class);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardActivateUserFormRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardActivateUserFormRequest.java
new file mode 100644
index 00000000..3d9a9687
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardActivateUserFormRequest.java
@@ -0,0 +1,70 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.JsonObject;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.Serializable;
+
+/**
+ * 会员卡激活,用户字段提交请求
+ *
+ * @author yuanqixun
+ * @date 2018-08-30
+ */
+@Data
+public class MemberCardActivateUserFormRequest implements Serializable {
+  @SerializedName("card_id")
+  private String cardId;
+
+  @SerializedName("service_statement")
+  private JsonObject serviceStatement;
+
+  @SerializedName("bind_old_card")
+  private JsonObject bindOldCard;
+
+  /**
+   * 必填项
+   */
+  @SerializedName("required_form")
+  private MemberCardUserForm requiredForm;
+
+  /**
+   * 可选项
+   */
+  @SerializedName("optional_form")
+  private MemberCardUserForm optionalForm;
+
+  /**
+   * 绑定老会员卡信息
+   *
+   * @param name
+   * @param url
+   */
+  public void setBindOldCard(String name, String url) {
+    if (StringUtils.isAnyEmpty(name, url)) {
+      return;
+    }
+    if (bindOldCard == null)
+      bindOldCard = new JsonObject();
+    bindOldCard.addProperty("name", name);
+    bindOldCard.addProperty("url", url);
+  }
+
+  /**
+   * 设置服务声明,用于放置商户会员卡守则
+   *
+   * @param name
+   * @param url
+   */
+  public void setServiceStatement(String name, String url) {
+    if (StringUtils.isAnyEmpty(name, url)) {
+      return;
+    }
+    if (serviceStatement == null)
+      serviceStatement = new JsonObject();
+    serviceStatement.addProperty("name", name);
+    serviceStatement.addProperty("url", url);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardActivateUserFormResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardActivateUserFormResult.java
new file mode 100644
index 00000000..c961676d
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardActivateUserFormResult.java
@@ -0,0 +1,29 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+@Data
+public class MemberCardActivateUserFormResult implements Serializable {
+  private Integer errcode;
+  private String errmsg;
+
+  public boolean isSuccess() {
+    return 0 == errcode;
+  }
+
+  public static MemberCardActivateUserFormResult fromJson(String json) {
+    return WxMpGsonBuilder.create().fromJson(json, MemberCardActivateUserFormResult.class);
+  }
+
+  @Override
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+
+}
+
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardCreateRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardCreateRequest.java
new file mode 100644
index 00000000..7e4139cb
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardCreateRequest.java
@@ -0,0 +1,21 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+@Data
+public class MemberCardCreateRequest implements Serializable {
+  @SerializedName("card_type")
+  private String cardType = "MEMBER_CARD";
+
+  @SerializedName("member_card")
+  private MemberCard memberCard;
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUserForm.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUserForm.java
new file mode 100644
index 00000000..14ef9f37
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUserForm.java
@@ -0,0 +1,92 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.mp.bean.card.enums.CardWechatFieldType;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 用户表单对象
+ *
+ * @author yuanqixun
+ * @date 2018-08-30
+ */
+@Data
+public class MemberCardUserForm implements Serializable {
+
+  /**
+   * 当前结构(required_form或者optional_form )内的字段是否允许用户激活后再次修改,
+   * 商户设置为true 时,需要接收相应事件通知处理修改事件
+   */
+  @SerializedName("can_modify")
+  private boolean canModify;
+
+  /**
+   * 富文本类型字段列表
+   */
+  @SerializedName("rich_field_list")
+  List richFieldList;
+
+  /**
+   * 文本选项类型列表
+   */
+  @SerializedName("custom_field_list")
+  private List customFieldList;
+
+
+  /**
+   * 微信格式化的选项类型
+   */
+  @SerializedName("common_field_id_list")
+  private List wechatFieldIdList;
+
+  /**
+   * 添加富文本类型字段
+   *
+   * @param fieldType
+   */
+  public void addRichField(MemberCardUserFormRichField field) {
+    if (field == null)
+      return;
+    if (richFieldList == null)
+      richFieldList = new ArrayList<>();
+    richFieldList.add(field);
+  }
+
+  /**
+   * 添加微信选项类型字段
+   *
+   * @param fieldType
+   */
+  public void addWechatField(CardWechatFieldType fieldType) {
+    if (fieldType == null)
+      return;
+    if (wechatFieldIdList == null)
+      wechatFieldIdList = new ArrayList<>();
+    wechatFieldIdList.add(fieldType.name());
+  }
+
+  /**
+   * 添加文本类型字段
+   *
+   * @param fieldType
+   */
+  public void addCustomField(String field) {
+    if (StringUtils.isBlank(field))
+      return;
+    if (customFieldList == null)
+      customFieldList = new ArrayList<>();
+    customFieldList.add(field);
+  }
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUserFormRichField.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUserFormRichField.java
new file mode 100644
index 00000000..6605f9b6
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUserFormRichField.java
@@ -0,0 +1,42 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.mp.bean.card.enums.CardRichFieldType;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 富文本字段
+ *
+ * @author yuanqixun
+ * @date 2018-08-30
+ */
+@Data
+public class MemberCardUserFormRichField {
+
+  /**
+   * 富文本类型
+   */
+  @SerializedName("type")
+  private CardRichFieldType type;
+
+  @SerializedName("name")
+  private String name;
+
+  @SerializedName("values")
+  private List valueList;
+
+  public void add(String value) {
+    if (valueList == null)
+      valueList = new ArrayList();
+    valueList.add(value);
+  }
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/PayInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/PayInfo.java
new file mode 100644
index 00000000..61fa8ccd
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/PayInfo.java
@@ -0,0 +1,27 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+/**
+ * 支付功能
+ * author:yuanqixun
+ * date:2018-08-25 00:33
+ */
+@Data
+public class PayInfo implements Serializable {
+
+  /**
+   * 刷卡功能
+   */
+  @SerializedName("swipe_card")
+  private SwipeCard swipeCard;
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Sku.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Sku.java
new file mode 100644
index 00000000..12db088d
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Sku.java
@@ -0,0 +1,27 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+/**
+ * 商品信息
+ * author:yuanqixun
+ * date:2018-08-25 00:32
+ */
+@Data
+public class Sku implements Serializable {
+
+  /**
+   * 卡券库存的数量,不支持填写0,上限为100000000。
+   */
+  @SerializedName("quantity")
+  private Integer quantity = 100000000;
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/SwipeCard.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/SwipeCard.java
new file mode 100644
index 00000000..fa176942
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/SwipeCard.java
@@ -0,0 +1,27 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+/**
+ * 刷卡功能
+ * author:yuanqixun
+ * date:2018-08-25 00:33
+ */
+@Data
+public class SwipeCard implements Serializable {
+
+  /**
+   * 是否设置该会员卡支持拉出微信支付刷卡界面
+   */
+  @SerializedName("is_swipe_card")
+  private boolean isSwipeCard;
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/TextImageList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/TextImageList.java
new file mode 100644
index 00000000..5836d956
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/TextImageList.java
@@ -0,0 +1,33 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+/**
+ * 图文列表
+ * author:yuanqixun
+ * date:2018-08-25 00:35
+ */
+@Data
+public class TextImageList implements Serializable {
+
+  /**
+   * 图片链接,必须调用 上传图片接口 上传图片获得链接,并在此填入, 否则报错
+   */
+  @SerializedName("image_url")
+  private String imageUrl;
+
+  /**
+   * 图文描述
+   */
+  @SerializedName("text")
+  private String text;
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/TimeLimit.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/TimeLimit.java
new file mode 100644
index 00000000..4c0d17d5
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/TimeLimit.java
@@ -0,0 +1,52 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+//子对象列表
+
+/**
+ * 使用时段限制
+ * author:yuanqixun
+ * date:2018-08-25 00:34
+ */
+@Data
+public class TimeLimit implements Serializable {
+
+  /**
+   * 限制类型枚举值,支持填入 MONDAY 周一 TUESDAY 周二 WEDNESDAY 周三 THURSDAY 周四 FRIDAY 周五 SATURDAY 周六 SUNDAY 周日 此处只控制显示, 不控制实际使用逻辑,不填默认不显示
+   */
+  @SerializedName("type")
+  private String type;
+
+  /**
+   * 起始时间(小时),当前type类型下的起始时间(小时) ,如当前结构体内填写了MONDAY, 此处填写了10,则此处表示周一 10:00可用
+   */
+  @SerializedName("begin_hour")
+  private Integer beginHour;
+
+  /**
+   * 起始时间(分钟),如当前结构体内填写了MONDAY, begin_hour填写10,此处填写了59, 则此处表示周一 10:59可用
+   */
+  @SerializedName("begin_minute")
+  private Integer beginMinute;
+
+  /**
+   * 结束时间(小时),如当前结构体内填写了MONDAY, 此处填写了20, 则此处表示周一 10:00-20:00可用
+   */
+  @SerializedName("end_hour")
+  private Integer endHour;
+
+  /**
+   * 结束时间(分钟),如当前结构体内填写了MONDAY, begin_hour填写10,此处填写了59, 则此处表示周一 10:59-00:59可用
+   */
+  @SerializedName("end_minute")
+  private Integer endMinute;
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/UseCondition.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/UseCondition.java
new file mode 100644
index 00000000..ff8fa830
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/UseCondition.java
@@ -0,0 +1,52 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+//子对象列表
+
+/**
+ * 使用门槛
+ * author:yuanqixun
+ * date:2018-08-25 00:35
+ */
+@Data
+public class UseCondition implements Serializable {
+
+  /**
+   * 指定可用的商品类目,仅用于代金券类型 ,填入后将在券面拼写适用于xxx
+   */
+  @SerializedName("accept_category")
+  private String acceptCategory;
+
+  /**
+   * 指定不可用的商品类目,仅用于代金券类型 ,填入后将在券面拼写不适用于xxxx
+   */
+  @SerializedName("reject_category")
+  private String rejectCategory;
+
+  /**
+   * 满减门槛字段,可用于兑换券和代金券 ,填入后将在全面拼写消费满xx元可用
+   */
+  @SerializedName("least_cost")
+  private Integer leastCost;
+
+  /**
+   * 购买xx可用类型门槛,仅用于兑换 ,填入后自动拼写购买xxx可用
+   */
+  @SerializedName("object_use_for")
+  private String objectUseFor;
+
+  /**
+   * 不可以与其他类型共享门槛,填写false时系统将在使用须知里 拼写“不可与其他优惠共享”, 填写true时系统将在使用须知里 拼写“可与其他优惠共享”, 默认为true
+   */
+  @SerializedName("can_use_with_other_discount")
+  private boolean canUseWithOtherDiscount;
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardCreateResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardCreateResult.java
new file mode 100644
index 00000000..24875d4e
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardCreateResult.java
@@ -0,0 +1,47 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+@Data
+public class WxMpCardCreateResult implements Serializable {
+  private static final long serialVersionUID = -128818731449449537L;
+  @SerializedName("card_id")
+  private String cardId;
+  private Integer errcode;
+  private String errmsg;
+
+  public boolean isSuccess() {
+    return 0 == errcode;
+  }
+
+  public static WxMpCardCreateResult fromJson(String json) {
+    return WxMpGsonBuilder.create().fromJson(json, WxMpCardCreateResult.class);
+  }
+
+  public static WxMpCardCreateResult failure(String errmsg) {
+    WxMpCardCreateResult result = new WxMpCardCreateResult();
+    result.setErrcode(500);
+    result.setErrmsg(errmsg);
+    return result;
+  }
+
+  public static WxMpCardCreateResult success() {
+    WxMpCardCreateResult result = new WxMpCardCreateResult();
+    result.setErrcode(0);
+    result.setErrmsg("ok");
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+
+}
+
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardLandingPageCreateRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardLandingPageCreateRequest.java
new file mode 100644
index 00000000..6a55a26a
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardLandingPageCreateRequest.java
@@ -0,0 +1,67 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+@Data
+public class WxMpCardLandingPageCreateRequest implements Serializable {
+
+  /**
+   * 页面的banner图片链接,须调用,建议尺寸为640*300。
+   */
+  private String banner;
+
+  /**
+   * 页面的title
+   */
+  @SerializedName("page_title")
+  private String title;
+
+  @SerializedName("can_share")
+  private boolean canShare;
+
+  /**
+   * 投放页面的场景值;
+   * SCENE_NEAR_BY 附近
+   * SCENE_MENU 自定义菜单
+   * SCENE_QRCODE 二维码
+   * SCENE_ARTICLE 公众号文章
+   * SCENE_H5 h5页面
+   * SCENE_IVR 自动回复
+   * SCENE_CARD_CUSTOM_CELL 卡券自定义cell
+   */
+  private String scene;
+
+  @SerializedName("card_list")
+  private JsonArray cardList;
+
+  public void addCard(String cardId, String thumbUrl) {
+    if (StringUtils.isNoneBlank(cardId, thumbUrl)) {
+      if (cardList == null)
+        cardList = new JsonArray();
+      JsonObject cardJson = new JsonObject();
+      cardJson.addProperty("card_id", cardId);
+      cardJson.addProperty("thumb_url", thumbUrl);
+      cardList.add(cardJson);
+    }
+  }
+
+  public static WxMpCardLandingPageCreateRequest fromJson(String json) {
+    return WxMpGsonBuilder.create().fromJson(json, WxMpCardLandingPageCreateRequest.class);
+  }
+
+  @Override
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+
+}
+
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardLandingPageCreateResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardLandingPageCreateResult.java
new file mode 100644
index 00000000..f99b5f18
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardLandingPageCreateResult.java
@@ -0,0 +1,40 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+@Data
+public class WxMpCardLandingPageCreateResult implements Serializable {
+  private Integer errcode;
+  private String errmsg;
+
+  /**
+   * 货架链接。
+   */
+  private String url;
+  /**
+   * 货架ID。货架的唯一标识
+   */
+  @SerializedName("page_id")
+  private Integer pageId;
+
+  public boolean isSuccess() {
+    return 0 == errcode;
+  }
+
+  public static WxMpCardLandingPageCreateResult fromJson(String json) {
+    return WxMpGsonBuilder.create().fromJson(json, WxMpCardLandingPageCreateResult.class);
+  }
+
+  @Override
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+
+}
+
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardQrcodeCreateResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardQrcodeCreateResult.java
new file mode 100644
index 00000000..46fb6323
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardQrcodeCreateResult.java
@@ -0,0 +1,40 @@
+package me.chanjar.weixin.mp.bean.card;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+@Data
+public class WxMpCardQrcodeCreateResult implements Serializable {
+  private static final long serialVersionUID = -128818731449449537L;
+  private Integer errcode;
+  private String errmsg;
+  private String ticket;
+
+  @SerializedName("expire_seconds")
+  private Integer expireSeconds;
+
+  private String url;
+
+  @SerializedName("show_qrcode_url")
+  private String showQrcodeUrl;
+
+  public boolean isSuccess() {
+    return 0 == errcode;
+  }
+
+  public static WxMpCardQrcodeCreateResult fromJson(String json) {
+    return WxMpGsonBuilder.create().fromJson(json, WxMpCardQrcodeCreateResult.class);
+  }
+
+  @Override
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+
+}
+
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/BusinessServiceType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/BusinessServiceType.java
new file mode 100644
index 00000000..3ae9cf89
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/BusinessServiceType.java
@@ -0,0 +1,21 @@
+package me.chanjar.weixin.mp.bean.card.enums;
+
+/**
+ * 商户提供服务类型
+ */
+public enum BusinessServiceType {
+  BIZ_SERVICE_DELIVER("外卖服务"),
+  BIZ_SERVICE_FREE_PARK("停车位"),
+  BIZ_SERVICE_WITH_PET("可带宠物"),
+  BIZ_SERVICE_FREE_WIFI("可带宠物");
+
+  private String description;
+
+  BusinessServiceType(String description) {
+    this.description = description;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardColor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardColor.java
new file mode 100644
index 00000000..0977cc92
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardColor.java
@@ -0,0 +1,35 @@
+package me.chanjar.weixin.mp.bean.card.enums;
+
+/**
+ * 会员卡颜色
+ *
+ * @author yuanqixun
+ * @date 2018-08-29
+ */
+public enum CardColor {
+  Color010("#63b359"),
+  Color020("#2c9f67"),
+  Color030("#509fc9"),
+  Color040("#5885cf"),
+  Color050("#9062c0"),
+  Color060("#d09a45"),
+  Color070("#e4b138"),
+  Color080("#ee903c"),
+  Color081("#f08500"),
+  Color082("#a9d92d"),
+  Color090("#dd6549"),
+  Color100("#cc463d"),
+  Color101("#cf3e36"),
+  Color102("#5E6671");
+
+  private String type;
+
+  CardColor(String type) {
+    this.type = type;
+  }
+
+  public String getValue() {
+    return type;
+  }
+
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardFieldType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardFieldType.java
new file mode 100644
index 00000000..4134f3e5
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardFieldType.java
@@ -0,0 +1,23 @@
+package me.chanjar.weixin.mp.bean.card.enums;
+
+/**
+ * 微信卡券激活字段类型
+ *
+ * @author yuanqixun
+ * @date 2018-08-30
+ */
+public enum CardFieldType {
+  COMMON_FIELD("微信选项"),
+  CUSTOM_FIELD("自定义选项"),
+  RICH_FIELD("自定义富文本类型");
+
+  private String description;
+
+  CardFieldType(String description) {
+    this.description = description;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardRichFieldType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardRichFieldType.java
new file mode 100644
index 00000000..40d4b79f
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardRichFieldType.java
@@ -0,0 +1,23 @@
+package me.chanjar.weixin.mp.bean.card.enums;
+
+/**
+ * 会员卡富文本字段类型
+ *
+ * @author yuanqixun
+ * @date 2018-08-30
+ */
+public enum CardRichFieldType {
+  FORM_FIELD_RADIO("自定义单选"),
+  FORM_FIELD_SELECT("自定义选择项"),
+  FORM_FIELD_CHECK_BOX("自定义多选");
+
+  private String description;
+
+  CardRichFieldType(String description) {
+    this.description = description;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardSceneType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardSceneType.java
new file mode 100644
index 00000000..ec5b9fcf
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardSceneType.java
@@ -0,0 +1,21 @@
+package me.chanjar.weixin.mp.bean.card.enums;
+
+public enum CardSceneType {
+  SCENE_NEAR_BY("附近"),
+  SCENE_MENU("自定义菜单"),
+  SCENE_QRCODE("二维码"),
+  SCENE_ARTICLE("公众号文章"),
+  SCENE_H5("H5"),
+  SCENE_IVR("自动回复"),
+  SCENE_CARD_CUSTOM_CELL("卡券自定义cell");
+
+  private String description;
+
+  CardSceneType(String description) {
+    this.description = description;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardWechatFieldType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardWechatFieldType.java
new file mode 100644
index 00000000..3a62c6f4
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardWechatFieldType.java
@@ -0,0 +1,31 @@
+package me.chanjar.weixin.mp.bean.card.enums;
+
+/**
+ * 微信卡券激活字段类型
+ *
+ * @author yuanqixun
+ * @date 2018-08-30
+ */
+public enum CardWechatFieldType {
+  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("兴趣爱好");
+
+  private String description;
+
+  CardWechatFieldType(String description) {
+    this.description = description;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/DateInfoType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/DateInfoType.java
new file mode 100644
index 00000000..bd8a2355
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/DateInfoType.java
@@ -0,0 +1,17 @@
+package me.chanjar.weixin.mp.bean.card.enums;
+
+public enum DateInfoType {
+  DATE_TYPE_PERMANENT("永久有效类型"),
+  DATE_TYPE_FIX_TIME_RANGE("固定日期"),
+  DATE_TYPE_FIX_TERM("固定时长");
+
+  private String description;
+
+  DateInfoType(String description) {
+    this.description = description;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeBaseResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeBaseResult.java
index df86ab4e..ee2a7d93 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeBaseResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeBaseResult.java
@@ -1,11 +1,13 @@
 package me.chanjar.weixin.mp.bean.datacube;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.JsonParser;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
-
-import java.io.Serializable;
 
 /**
  * 
@@ -29,7 +31,7 @@ public abstract class WxDataCubeBaseResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserCumulate.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserCumulate.java
index ee0db76a..5275e140 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserCumulate.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserCumulate.java
@@ -1,20 +1,24 @@
 package me.chanjar.weixin.mp.bean.datacube;
 
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.JsonParser;
 import com.google.gson.reflect.TypeToken;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-import java.util.Date;
-import java.util.List;
-
 /**
  * 
  * 累计用户数据接口的返回JSON数据包
  * 详情查看文档:用户分析数据接口
  * 
+ * + * @author BinaryWang */ @Data public class WxDataCubeUserCumulate implements Serializable { @@ -35,6 +39,6 @@ public class WxDataCubeUserCumulate implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserSummary.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserSummary.java index 48c53a7e..06d93821 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserSummary.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserSummary.java @@ -1,15 +1,17 @@ package me.chanjar.weixin.mp.bean.datacube; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; import lombok.Data; -import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import java.io.Serializable; -import java.util.Date; -import java.util.List; - /** *
  * 用户增减数据接口的返回JSON数据包
@@ -39,6 +41,6 @@ public class WxDataCubeUserSummary implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceMsg.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceMsg.java
index 4128a9f8..9e12a5bb 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceMsg.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceMsg.java
@@ -1,9 +1,11 @@
 package me.chanjar.weixin.mp.bean.device;
 
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
-import me.chanjar.weixin.common.util.ToStringUtils;
 
 /**
  * @author keungtung.
@@ -24,6 +26,6 @@ public class WxDeviceMsg extends AbstractDeviceBean {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfSessionRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfSessionRequest.java
index 2f077d3f..6cc00f5c 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfSessionRequest.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfSessionRequest.java
@@ -1,12 +1,14 @@
 package me.chanjar.weixin.mp.bean.kefu.request;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-
 @Data
 public class WxMpKfSessionRequest implements Serializable {
   private static final long serialVersionUID = -5451863610674856927L;
@@ -30,7 +32,7 @@ public class WxMpKfSessionRequest implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   public String toJson() {
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfInfo.java
index 60b5370d..76f25d9b 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfInfo.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfInfo.java
@@ -1,11 +1,13 @@
 package me.chanjar.weixin.mp.bean.kefu.result;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.Expose;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
-
-import java.io.Serializable;
 
 /**
  * 客服基本信息以及客服在线状态信息
@@ -79,7 +81,7 @@ public class WxMpKfInfo implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfList.java
index 3d9a8872..d7ac2043 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfList.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfList.java
@@ -1,13 +1,15 @@
 package me.chanjar.weixin.mp.bean.kefu.result;
 
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-import java.util.List;
-
 /**
  * @author Binary Wang
  */
@@ -24,7 +26,7 @@ public class WxMpKfList implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgList.java
index ee2f7514..01b262dd 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgList.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgList.java
@@ -1,13 +1,15 @@
 package me.chanjar.weixin.mp.bean.kefu.result;
 
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-import java.util.List;
-
 /**
  *
  * @author Binary Wang
@@ -32,6 +34,6 @@ public class WxMpKfMsgList implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java
index baba81da..fc3a1471 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java
@@ -1,10 +1,12 @@
 package me.chanjar.weixin.mp.bean.kefu.result;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
-
-import java.io.Serializable;
 
 /**
  *
@@ -47,7 +49,7 @@ public class WxMpKfMsgRecord implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   public String getWorker() {
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfOnlineList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfOnlineList.java
index cb5f9071..e1e8c298 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfOnlineList.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfOnlineList.java
@@ -1,13 +1,15 @@
 package me.chanjar.weixin.mp.bean.kefu.result;
 
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-import java.util.List;
-
 /**
  * @author Binary Wang
  */
@@ -24,7 +26,7 @@ public class WxMpKfOnlineList implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSession.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSession.java
index 16110254..c5e9b02a 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSession.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSession.java
@@ -1,10 +1,12 @@
 package me.chanjar.weixin.mp.bean.kefu.result;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
-
-import java.io.Serializable;
 
 /**
  * @author Binary Wang
@@ -41,7 +43,7 @@ public class WxMpKfSession implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionGetResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionGetResult.java
index 5f4b318c..628bd7c4 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionGetResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionGetResult.java
@@ -1,12 +1,14 @@
 package me.chanjar.weixin.mp.bean.kefu.result;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-
 /**
  * @author Binary Wang
  */
@@ -32,7 +34,7 @@ public class WxMpKfSessionGetResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionList.java
index e12def66..4aacdd1e 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionList.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionList.java
@@ -1,13 +1,15 @@
 package me.chanjar.weixin.mp.bean.kefu.result;
 
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-import java.util.List;
-
 /**
  * @author Binary Wang
  */
@@ -28,7 +30,7 @@ public class WxMpKfSessionList implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionWaitCaseList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionWaitCaseList.java
index 872ba7db..69b5b915 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionWaitCaseList.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionWaitCaseList.java
@@ -1,13 +1,15 @@
 package me.chanjar.weixin.mp.bean.kefu.result;
 
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-import java.util.List;
-
 /**
  * @author Binary Wang
  */
@@ -34,7 +36,7 @@ public class WxMpKfSessionWaitCaseList implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialCountResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialCountResult.java
index 0bb33841..ba457e79 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialCountResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialCountResult.java
@@ -1,10 +1,15 @@
 package me.chanjar.weixin.mp.bean.material;
 
-import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
-
 import java.io.Serializable;
 
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import lombok.Data;
+
+/**
+ * @author codepiano
+ */
 @Data
 public class WxMpMaterialCountResult implements Serializable {
   private static final long serialVersionUID = -5568772662085874138L;
@@ -16,7 +21,7 @@ public class WxMpMaterialCountResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialFileBatchGetResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialFileBatchGetResult.java
index 4f445a28..3d6e9353 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialFileBatchGetResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialFileBatchGetResult.java
@@ -1,12 +1,17 @@
 package me.chanjar.weixin.mp.bean.material;
 
-import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
-
 import java.io.Serializable;
 import java.util.Date;
 import java.util.List;
 
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import lombok.Data;
+
+/**
+ * @author codepiano
+ */
 @Data
 public class WxMpMaterialFileBatchGetResult implements Serializable {
   private static final long serialVersionUID = -560388368297267884L;
@@ -17,7 +22,7 @@ public class WxMpMaterialFileBatchGetResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   @Data
@@ -29,7 +34,7 @@ public class WxMpMaterialFileBatchGetResult implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringUtils.toSimpleString(this);
+      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
     }
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNews.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNews.java
index 2a2439da..16f787a3 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNews.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNews.java
@@ -1,14 +1,19 @@
 package me.chanjar.weixin.mp.bean.material;
 
-import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
-import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
-
 import java.io.Serializable;
-import java.util.Date;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+
+/**
+ * @author codepiano
+ */
 @Data
 public class WxMpMaterialNews implements Serializable {
   private static final long serialVersionUID = -3283203652013494976L;
@@ -110,7 +115,7 @@ public class WxMpMaterialNews implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringUtils.toSimpleString(this);
+      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
     }
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNewsBatchGetResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNewsBatchGetResult.java
index 77fe8b56..47e6cb53 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNewsBatchGetResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNewsBatchGetResult.java
@@ -1,12 +1,14 @@
 package me.chanjar.weixin.mp.bean.material;
 
-import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
-
 import java.io.Serializable;
 import java.util.Date;
 import java.util.List;
 
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import lombok.Data;
+
 @Data
 public class WxMpMaterialNewsBatchGetResult implements Serializable {
   private static final long serialVersionUID = -1617952797921001666L;
@@ -17,7 +19,7 @@ public class WxMpMaterialNewsBatchGetResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   @Data
@@ -28,7 +30,7 @@ public class WxMpMaterialNewsBatchGetResult implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringUtils.toSimpleString(this);
+      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
     }
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialUploadResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialUploadResult.java
index 6a4630e5..15744ce5 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialUploadResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialUploadResult.java
@@ -1,11 +1,13 @@
 package me.chanjar.weixin.mp.bean.material;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-
 @Data
 public class WxMpMaterialUploadResult implements Serializable {
   private static final long serialVersionUID = -128818731449449537L;
@@ -20,7 +22,7 @@ public class WxMpMaterialUploadResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardCreateMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardCreateMessage.java
new file mode 100644
index 00000000..bd8fccb4
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardCreateMessage.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.mp.bean.membercard;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.mp.bean.card.MemberCardCreateRequest;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+@Data
+public final class WxMpMemberCardCreateMessage implements Serializable {
+
+  @SerializedName("card")
+  private MemberCardCreateRequest cardCreateRequest;
+
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+
+  public static WxMpMemberCardCreateMessage fromJson(String json) {
+    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpMemberCardCreateMessage.class);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResult.java
index 355b67df..96b8212d 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResult.java
@@ -1,11 +1,13 @@
 package me.chanjar.weixin.mp.bean.membercard;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-
 /**
  * 
  * 用于 `7 更新会员信息` 的接口调用后的返回结果
@@ -32,7 +34,7 @@ public class WxMpMemberCardUpdateResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   public static WxMpMemberCardUpdateResult fromJson(String json) {
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java
index d87f4ba3..705dba78 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java
@@ -1,11 +1,13 @@
 package me.chanjar.weixin.mp.bean.membercard;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-
 /**
  * 
  * 拉取会员信息返回的结果
@@ -45,7 +47,7 @@ public class WxMpMemberCardUserInfoResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   public static WxMpMemberCardUserInfoResult fromJson(String json) {
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResult.java
index b8258b1d..2c370eaf 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResult.java
@@ -1,12 +1,14 @@
 package me.chanjar.weixin.mp.bean.menu;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
-import java.io.Serializable;
-
 /**
  * 
  * Created by Binary Wang on 2016-11-25.
@@ -30,7 +32,7 @@ public class WxMpGetSelfMenuInfoResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java
index 1847be3f..e36a2b23 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java
@@ -1,15 +1,17 @@
 package me.chanjar.weixin.mp.bean.menu;
 
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import me.chanjar.weixin.common.bean.menu.WxMenuButton;
 import me.chanjar.weixin.common.bean.menu.WxMenuRule;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
-import java.io.Serializable;
-import java.util.List;
-
 /**
  * 
  *   公众号专用的菜单类,可能包含个性化菜单
@@ -34,7 +36,7 @@ public class WxMpMenu implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   public String toJson() {
@@ -54,7 +56,7 @@ public class WxMpMenu implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringUtils.toSimpleString(this);
+      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
     }
 
   }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java
index 2532a092..b9d8e941 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java
@@ -1,13 +1,15 @@
 package me.chanjar.weixin.mp.bean.menu;
 
-import com.google.gson.annotations.SerializedName;
-import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
-
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
 /**
  * 
  * Created by Binary Wang on 2016-11-25.
@@ -27,7 +29,7 @@ public class WxMpSelfMenuInfo implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   @Data
@@ -87,7 +89,7 @@ public class WxMpSelfMenuInfo implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringUtils.toSimpleString(this);
+      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
     }
 
     @Data
@@ -99,7 +101,7 @@ public class WxMpSelfMenuInfo implements Serializable {
 
       @Override
       public String toString() {
-        return ToStringUtils.toSimpleString(this);
+        return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
       }
     }
 
@@ -112,7 +114,7 @@ public class WxMpSelfMenuInfo implements Serializable {
 
       @Override
       public String toString() {
-        return ToStringUtils.toSimpleString(this);
+        return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
       }
 
       @Data
@@ -158,7 +160,7 @@ public class WxMpSelfMenuInfo implements Serializable {
 
         @Override
         public String toString() {
-          return ToStringUtils.toSimpleString(this);
+          return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
         }
 
       }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/HardWare.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/HardWare.java
index 6cef393e..f29321d4 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/HardWare.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/HardWare.java
@@ -1,13 +1,15 @@
 package me.chanjar.weixin.mp.bean.message;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import com.thoughtworks.xstream.annotations.XStreamConverter;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
 
-import java.io.Serializable;
-
 /**
  * 
  *  Created by BinaryWang on 2017/5/4.
@@ -35,6 +37,6 @@ public class HardWare implements Serializable{
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/ScanCodeInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/ScanCodeInfo.java
index 630090c2..2af977ca 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/ScanCodeInfo.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/ScanCodeInfo.java
@@ -1,13 +1,15 @@
 package me.chanjar.weixin.mp.bean.message;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import com.thoughtworks.xstream.annotations.XStreamConverter;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
 
-import java.io.Serializable;
-
 /**
  * 
  *  Created by BinaryWang on 2017/5/4.
@@ -20,31 +22,23 @@ import java.io.Serializable;
 public class ScanCodeInfo implements Serializable {
   private static final long serialVersionUID = 4745181270645050122L;
 
+  /**
+   * 扫描类型,一般是qrcode.
+   */
   @XStreamAlias("ScanType")
   @XStreamConverter(value = XStreamCDataConverter.class)
   private String scanType;
+
+  /**
+   * 扫描结果,即二维码对应的字符串信息.
+   */
   @XStreamAlias("ScanResult")
   @XStreamConverter(value = XStreamCDataConverter.class)
   private String scanResult;
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
-  /**
-   * 扫描类型,一般是qrcode
-   */
-  public String getScanType() {
-    return this.scanType;
-  }
-
-  /**
-   * 扫描结果,即二维码对应的字符串信息
-   */
-  public String getScanResult() {
-    return this.scanResult;
-  }
-
-
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/SendLocationInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/SendLocationInfo.java
index c7c8fda6..5d725557 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/SendLocationInfo.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/SendLocationInfo.java
@@ -1,13 +1,15 @@
 package me.chanjar.weixin.mp.bean.message;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import com.thoughtworks.xstream.annotations.XStreamConverter;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
 
-import java.io.Serializable;
-
 /**
  * 
  *  Created by BinaryWang on 2017/5/4.
@@ -42,6 +44,6 @@ public class SendLocationInfo implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/SendPicsInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/SendPicsInfo.java
index 51806768..318e7cee 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/SendPicsInfo.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/SendPicsInfo.java
@@ -1,15 +1,17 @@
 package me.chanjar.weixin.mp.bean.message;
 
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import com.thoughtworks.xstream.annotations.XStreamConverter;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
 
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * 
  *  Created by BinaryWang on 2017/5/4.
@@ -30,7 +32,7 @@ public class SendPicsInfo implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   @XStreamAlias("item")
@@ -44,7 +46,7 @@ public class SendPicsInfo implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringUtils.toSimpleString(this);
+      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
     }
 
   }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java
index 8c67e036..ae476331 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java
@@ -1,23 +1,26 @@
 package me.chanjar.weixin.mp.bean.message;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import com.thoughtworks.xstream.annotations.XStreamConverter;
 import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.api.WxConsts;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
 import me.chanjar.weixin.mp.api.WxMpConfigStorage;
 import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil;
 import me.chanjar.weixin.mp.util.xml.XStreamTransformer;
-import org.apache.commons.io.IOUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Serializable;
 
 /**
  * 
- * 微信推送过来的消息,xml格式
+ * 微信推送过来的消息,xml格式.
  * 部分未注释的字段的解释请查阅相关微信开发文档:
  * 接收普通消息
  * 接收事件推送
@@ -25,8 +28,9 @@ import java.io.Serializable;
  *
  * @author chanjarster
  */
-@XStreamAlias("xml")
 @Data
+@Slf4j
+@XStreamAlias("xml")
 public class WxMpXmlMessage implements Serializable {
   private static final long serialVersionUID = -3586245291677274914L;
 
@@ -129,28 +133,29 @@ public class WxMpXmlMessage implements Serializable {
   // 群发消息返回的结果
   ///////////////////////////////////////
   /**
-   * 群发的结果
+   * 群发的结果.
    */
   @XStreamAlias("Status")
   @XStreamConverter(value = XStreamCDataConverter.class)
   private String status;
   /**
-   * group_id下粉丝数;或者openid_list中的粉丝数
+   * group_id下粉丝数;或者openid_list中的粉丝数.
    */
   @XStreamAlias("TotalCount")
   private Integer totalCount;
   /**
-   * 过滤(过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超4条的过滤)后,准备发送的粉丝数,原则上,filterCount = sentCount + errorCount
+   * 过滤(过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超4条的过滤)后,准备发送的粉丝数.
+   * 原则上,filterCount = sentCount + errorCount
    */
   @XStreamAlias("FilterCount")
   private Integer filterCount;
   /**
-   * 发送成功的粉丝数
+   * 发送成功的粉丝数.
    */
   @XStreamAlias("SentCount")
   private Integer sentCount;
   /**
-   * 发送失败的粉丝数
+   * 发送失败的粉丝数.
    */
   @XStreamAlias("ErrorCount")
   private Integer errorCount;
@@ -159,17 +164,17 @@ public class WxMpXmlMessage implements Serializable {
   // 客服会话管理相关事件推送
   ///////////////////////////////////////
   /**
-   * 创建或关闭客服会话时的客服帐号
+   * 创建或关闭客服会话时的客服帐号.
    */
   @XStreamAlias("KfAccount")
   private String kfAccount;
   /**
-   * 转接客服会话时的转入客服帐号
+   * 转接客服会话时的转入客服帐号.
    */
   @XStreamAlias("ToKfAccount")
   private String toKfAccount;
   /**
-   * 转接客服会话时的转出客服帐号
+   * 转接客服会话时的转出客服帐号.
    */
   @XStreamAlias("FromKfAccount")
   private String fromKfAccount;
@@ -177,6 +182,7 @@ public class WxMpXmlMessage implements Serializable {
   ///////////////////////////////////////
   // 卡券相关事件推送
   ///////////////////////////////////////
+
   @XStreamAlias("CardId")
   @XStreamConverter(value = XStreamCDataConverter.class)
   private String cardId;
@@ -185,8 +191,11 @@ public class WxMpXmlMessage implements Serializable {
   @XStreamConverter(value = XStreamCDataConverter.class)
   private String friendUserName;
 
+  /**
+   * 是否为转赠,1代表是,0代表否.
+   */
   @XStreamAlias("IsGiveByFriend")
-  private Integer isGiveByFriend; // 是否为转赠,1代表是,0代表否
+  private Integer isGiveByFriend;
 
   @XStreamAlias("UserCardCode")
   @XStreamConverter(value = XStreamCDataConverter.class)
@@ -200,14 +209,14 @@ public class WxMpXmlMessage implements Serializable {
   private Integer outerId;
 
   /**
-   * 用户删除会员卡后可重新找回,当用户本次操作为找回时,该值为1,否则为0
+   * 用户删除会员卡后可重新找回,当用户本次操作为找回时,该值为1,否则为0.
    */
   @XStreamAlias("IsRestoreMemberCard")
   private String isRestoreMemberCard;
 
   /**
    * 
-   * 领取场景值,用于领取渠道数据统计。可在生成二维码接口及添加Addcard接口中自定义该字段的字符串值。
+   * 领取场景值,用于领取渠道数据统计。可在生成二维码接口及添加Addcard接口中自定义该字段的字符串值.
    * 核销卡券时:开发者发起核销时传入的自定义参数,用于进行核销渠道统计
    * 另外:
    * 官网文档中,微信卡券>>卡券事件推送>>2.7 进入会员卡事件推送 user_view_card
@@ -218,43 +227,45 @@ public class WxMpXmlMessage implements Serializable {
   private String outerStr;
 
   /**
-   * 是否转赠退回,0代表不是,1代表是。
+   * 是否转赠退回,0代表不是,1代表是.
    */
   @XStreamAlias("IsReturnBack")
   private String isReturnBack;
 
   /**
-   * 是否是群转赠,0代表不是,1代表是。
+   * 是否是群转赠,0代表不是,1代表是.
    */
   @XStreamAlias("IsChatRoom")
   private String isChatRoom;
 
   /**
-   * 核销来源。支持开发者统计API核销(FROM_API)、公众平台核销(FROM_MP)、卡券商户助手核销(FROM_MOBILE_HELPER)(核销员微信号)
+   * 核销来源.
+   * 支持开发者统计API核销(FROM_API)、公众平台核销(FROM_MP)、卡券商户助手核销(FROM_MOBILE_HELPER)(核销员微信号)
    */
   @XStreamAlias("ConsumeSource")
   private String consumeSource;
 
   /**
-   * 门店名称,当前卡券核销的门店名称(只有通过自助核销和买单核销时才会出现该字段)
+   * 门店名称.
+   * 当前卡券核销的门店名称(只有通过自助核销和买单核销时才会出现该字段)
    */
   @XStreamAlias("LocationName")
   private String locationName;
 
   /**
-   * 核销该卡券核销员的openid(只有通过卡券商户助手核销时才会出现)
+   * 核销该卡券核销员的openid(只有通过卡券商户助手核销时才会出现).
    */
   @XStreamAlias("StaffOpenId")
   private String staffOpenId;
 
   /**
-   * 自助核销时,用户输入的验证码
+   * 自助核销时,用户输入的验证码.
    */
   @XStreamAlias("VerifyCode")
   private String verifyCode;
 
   /**
-   * 自助核销时,用户输入的备注金额
+   * 自助核销时,用户输入的备注金额.
    */
   @XStreamAlias("RemarkAmount")
   private String remarkAmount;
@@ -262,7 +273,7 @@ public class WxMpXmlMessage implements Serializable {
   /**
    * 
    * 官网文档中,微信卡券>>卡券事件推送>>2.10 库存报警事件card_sku_remind
-   * Detail:报警详细信息
+   * Detail:报警详细信息.
    * 
*/ @XStreamAlias("Detail") @@ -271,7 +282,7 @@ public class WxMpXmlMessage implements Serializable { /** *
    * 官网文档中,微信卡券>>卡券事件推送>>2.9 会员卡内容更新事件 update_member_card
-   * ModifyBonus:变动的积分值
+   * ModifyBonus:变动的积分值.
    * 
*/ @XStreamAlias("ModifyBonus") @@ -280,7 +291,7 @@ public class WxMpXmlMessage implements Serializable { /** *
    * 官网文档中,微信卡券>>卡券事件推送>>2.9 会员卡内容更新事件 update_member_card
-   * ModifyBalance:变动的余额值
+   * ModifyBalance:变动的余额值.
    * 
*/ @XStreamAlias("ModifyBalance") @@ -289,7 +300,7 @@ public class WxMpXmlMessage implements Serializable { /** *
    * 官网文档中,微信卡券>>卡券事件推送>>2.6 买单事件推送 User_pay_from_pay_cell
-   * TransId:微信支付交易订单号(只有使用买单功能核销的卡券才会出现)
+   * TransId:微信支付交易订单号(只有使用买单功能核销的卡券才会出现).
    * 
*/ @XStreamAlias("TransId") @@ -331,33 +342,105 @@ public class WxMpXmlMessage implements Serializable { @XStreamAlias("SendLocationInfo") private SendLocationInfo sendLocationInfo = new SendLocationInfo(); + /** + * 审核不通过原因 + */ + @XStreamAlias("RefuseReason") + private String refuseReason; + + /** + * 是否为朋友推荐,0代表否,1代表是 + */ + @XStreamAlias("IsRecommendByFriend") + private String isRecommendByFriend; + + /** + * 购买券点时,实际支付成功的时间 + */ + @XStreamAlias("PayFinishTime") + private String payFinishTime; + + /** + * 购买券点时,支付二维码的生成时间 + */ + @XStreamAlias("CreateOrderTime") + private String createOrderTime; + + /** + * 购买券点时,支付二维码的生成时间 + */ + @XStreamAlias("Desc") + private String desc; + + /** + * 剩余免费券点数量 + */ + @XStreamAlias("FreeCoinCount") + private String freeCoinCount; + + /** + * 剩余付费券点数量 + */ + @XStreamAlias("PayCoinCount") + private String payCoinCount; + + /** + * 本次变动的免费券点数量 + */ + @XStreamAlias("RefundFreeCoinCount") + private String refundFreeCoinCount; + + /** + * 本次变动的付费券点数量 + */ + @XStreamAlias("RefundPayCoinCount") + private String refundPayCoinCount; + + /** + *
+   *    所要拉取的订单类型 ORDER_TYPE_SYS_ADD 平台赠送券点 ORDER_TYPE_WXPAY 充值券点 ORDER_TYPE_REFUND 库存未使用回退券点
+   *    ORDER_TYPE_REDUCE 券点兑换库存 ORDER_TYPE_SYS_REDUCE 平台扣减
+   * 
+ */ + @XStreamAlias("OrderType") + private String orderType; + + /** + * 系统备注,说明此次变动的缘由,如开通账户奖励、门店奖励、核销奖励以及充值、扣减。 + */ + @XStreamAlias("Memo") + private String memo; + + /** + * 所开发票的详情 + */ + @XStreamAlias("ReceiptInfo") + private String receiptInfo; + + /////////////////////////////////////// // 门店审核事件推送 /////////////////////////////////////// /** - * UniqId - * 商户自己内部ID,即字段中的sid + * 商户自己内部ID,即字段中的sid. */ @XStreamAlias("UniqId") private String storeUniqId; /** - * PoiId - * 微信的门店ID,微信内门店唯一标示ID + * 微信的门店ID,微信内门店唯一标示ID. */ @XStreamAlias("PoiId") private String poiId; /** - * Result - * 审核结果,成功succ 或失败fail + * 审核结果,成功succ 或失败fail. */ @XStreamAlias("Result") private String result; /** - * msg - * 成功的通知信息,或审核失败的驳回理由 + * 成功的通知信息,或审核失败的驳回理由. */ @XStreamAlias("msg") private String msg; @@ -366,46 +449,74 @@ public class WxMpXmlMessage implements Serializable { // 微信认证事件推送 /////////////////////////////////////// /** - * ExpiredTime - * 资质认证成功/名称认证成功: 有效期 (整形),指的是时间戳,将于该时间戳认证过期 + * 资质认证成功/名称认证成功: 有效期 (整形),指的是时间戳,将于该时间戳认证过期. * 年审通知: 有效期 (整形),指的是时间戳,将于该时间戳认证过期,需尽快年审 * 认证过期失效通知: 有效期 (整形),指的是时间戳,表示已于该时间戳认证过期,需要重新发起微信认证 */ @XStreamAlias("ExpiredTime") private Long expiredTime; /** - * FailTime - * 失败发生时间 (整形),时间戳 + * 失败发生时间 (整形),时间戳. */ @XStreamAlias("FailTime") private Long failTime; /** - * FailReason - * 认证失败的原因 + * 认证失败的原因. */ @XStreamAlias("FailReason") private String failReason; + /////////////////////////////////////// + // 微信小店 6.1订单付款通知 + /////////////////////////////////////// + /** + * 订单ID. + */ + @XStreamAlias("OrderId") + @XStreamConverter(value = XStreamCDataConverter.class) + private String orderId; + + /** + * 订单状态. + */ + @XStreamAlias("OrderStatus") + private String orderStatus; + + /** + * 商品ID. + */ + @XStreamAlias("ProductId") + @XStreamConverter(value = XStreamCDataConverter.class) + private String productId; + + /** + * 商品SKU信息. + */ + @XStreamAlias("SkuInfo") + @XStreamConverter(value = XStreamCDataConverter.class) + private String skuInfo; /////////////////////////////////////// // 微信硬件平台相关事件推送 /////////////////////////////////////// /** - * 设备类型,目前为"公众账号原始ID" + * 设备类型. + * 目前为"公众账号原始ID" */ @XStreamAlias("DeviceType") @XStreamConverter(value = XStreamCDataConverter.class) private String deviceType; /** - * 设备ID,第三方提供 + * 设备ID. + * 第三方提供 */ @XStreamAlias("DeviceID") @XStreamConverter(value = XStreamCDataConverter.class) private String deviceId; /** - * 微信用户账号的OpenID + * 微信用户账号的OpenID. */ @XStreamAlias("OpenID") @XStreamConverter(value = XStreamCDataConverter.class) @@ -415,13 +526,17 @@ public class WxMpXmlMessage implements Serializable { private HardWare hardWare = new HardWare(); /** - * 请求类型:0:退订设备状态;1:心跳;(心跳的处理方式跟订阅一样)2:订阅设备状态 + * 请求类型. + * 0:退订设备状态; + * 1:心跳;(心跳的处理方式跟订阅一样) + * 2:订阅设备状态 */ @XStreamAlias("OpType") private Integer opType; /** - * 设备状态:0:未连接;1:已连接 + * 设备状态. + * 0:未连接;1:已连接 */ @XStreamAlias("DeviceStatus") private Integer deviceStatus; @@ -437,7 +552,7 @@ public class WxMpXmlMessage implements Serializable { } /** - * 从加密字符串转换 + * 从加密字符串转换. * * @param encryptedXml 密文 * @param wxMpConfigStorage 配置存储器对象 @@ -445,21 +560,18 @@ public class WxMpXmlMessage implements Serializable { * @param nonce 随机串 * @param msgSignature 签名串 */ - public static WxMpXmlMessage fromEncryptedXml(String encryptedXml, - WxMpConfigStorage wxMpConfigStorage, String timestamp, String nonce, - String msgSignature) { + public static WxMpXmlMessage fromEncryptedXml(String encryptedXml, WxMpConfigStorage wxMpConfigStorage, + String timestamp, String nonce, String msgSignature) { WxMpCryptUtil cryptUtil = new WxMpCryptUtil(wxMpConfigStorage); - String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, - encryptedXml); + String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml); + log.debug("解密后的原始xml消息内容:{}", plainText); return fromXml(plainText); } - public static WxMpXmlMessage fromEncryptedXml(InputStream is, - WxMpConfigStorage wxMpConfigStorage, String timestamp, String nonce, - String msgSignature) { + public static WxMpXmlMessage fromEncryptedXml(InputStream is, WxMpConfigStorage wxMpConfigStorage, String timestamp, + String nonce, String msgSignature) { try { - return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxMpConfigStorage, - timestamp, nonce, msgSignature); + return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxMpConfigStorage, timestamp, nonce, msgSignature); } catch (IOException e) { throw new RuntimeException(e); } @@ -491,7 +603,6 @@ public class WxMpXmlMessage implements Serializable { * {@link WxConsts.XmlMsgType#NEWS} * {@link WxConsts.XmlMsgType#MUSIC} *
- * */ public void setMsgType(String msgType) { this.msgType = msgType; @@ -499,7 +610,7 @@ public class WxMpXmlMessage implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCardResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCardResult.java index 2f478a20..7cbf9b7f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCardResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCardResult.java @@ -1,11 +1,13 @@ package me.chanjar.weixin.mp.bean.result; +import java.io.Serializable; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import lombok.Data; -import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.mp.bean.WxMpCard; -import java.io.Serializable; - /** * 卡券查询Code,核销Code接口返回结果 * @@ -30,7 +32,7 @@ public class WxMpCardResult implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfo.java index 52bebcf9..d68fcacf 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfo.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfo.java @@ -1,23 +1,26 @@ package me.chanjar.weixin.mp.bean.result; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; import lombok.Data; -import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.common.util.json.WxBooleanTypeAdapter; import me.chanjar.weixin.common.util.json.WxDateTypeAdapter; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import java.io.Serializable; -import java.util.Date; -import java.util.List; - /** *
- * 公众号的自动回复规则
+ * 公众号的自动回复规则.
  * Created by Binary Wang on 2017-7-8.
- * @author Binary Wang
  * 
+ * + * @author Binary Wang */ @Data public class WxMpCurrentAutoReplyInfo implements Serializable { @@ -25,7 +28,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } public static WxMpCurrentAutoReplyInfo fromJson(String json) { @@ -55,7 +58,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } @SerializedName("rule_name") @@ -82,7 +85,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } private String type; @@ -99,7 +102,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } private List list; @@ -112,7 +115,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } @SerializedName("cover_url") @@ -136,7 +139,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } private String type; @@ -152,7 +155,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } private List list; @@ -164,7 +167,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } private String type; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java index d0d2a9d8..392cc046 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java @@ -1,11 +1,13 @@ package me.chanjar.weixin.mp.bean.result; +import java.io.Serializable; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import lombok.Data; -import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import java.io.Serializable; - /** *
  * 群发消息一发送就返回的结果
@@ -32,7 +34,7 @@ public class WxMpMassSendResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java
index a1362725..98410891 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java
@@ -1,14 +1,16 @@
 package me.chanjar.weixin.mp.bean.result;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-
 /**
  * 
- * 上传群发用的素材的结果
+ * 上传群发用的素材的结果.
  * 视频和图文消息需要在群发前上传素材
  * 
* @@ -28,7 +30,7 @@ public class WxMpMassUploadResult implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java index b0429cf7..33fa172d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java @@ -1,11 +1,13 @@ package me.chanjar.weixin.mp.bean.result; +import java.io.Serializable; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import lombok.Data; -import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import java.io.Serializable; - /** * https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842 */ @@ -35,6 +37,6 @@ public class WxMpOAuth2AccessToken implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java index 5d9c6bce..818c4c5f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java @@ -4,11 +4,13 @@ import java.io.Serializable; import java.lang.reflect.Type; import java.util.List; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; import lombok.Data; -import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** @@ -87,7 +89,7 @@ public class WxMpUser implements Serializable { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreBaseInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreBaseInfo.java index 007826bb..03f814af 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreBaseInfo.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreBaseInfo.java @@ -1,18 +1,20 @@ package me.chanjar.weixin.mp.bean.store; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.List; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.annotations.SerializedName; import lombok.Builder; import lombok.Data; import me.chanjar.weixin.common.annotation.Required; -import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import java.io.Serializable; -import java.math.BigDecimal; -import java.util.List; - /** *
  *  门店基础信息
@@ -177,7 +179,7 @@ public class WxMpStoreBaseInfo implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   public String toJson() {
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreInfo.java
index a72fb5d4..3002e190 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreInfo.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreInfo.java
@@ -1,11 +1,16 @@
 package me.chanjar.weixin.mp.bean.store;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
-
-import java.io.Serializable;
 
+/**
+ * @author BinaryWang
+ */
 @Data
 public class WxMpStoreInfo implements Serializable{
   private static final long serialVersionUID = 7300598931768355461L;
@@ -15,6 +20,6 @@ public class WxMpStoreInfo implements Serializable{
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreListResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreListResult.java
index 5fdfa944..079b5c1c 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreListResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreListResult.java
@@ -1,13 +1,15 @@
 package me.chanjar.weixin.mp.bean.store;
 
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-import java.util.List;
-
 /**
  * 
  * 门店列表结果类
@@ -21,22 +23,22 @@ public class WxMpStoreListResult implements Serializable {
   private static final long serialVersionUID = 5388907559949538663L;
 
   /**
-   * 错误码,0为正常
+   * 错误码,0为正常.
    */
   @SerializedName("errcode")
   private Integer errCode;
   /**
-   * 错误信息
+   * 错误信息.
    */
   @SerializedName("errmsg")
   private String errMsg;
   /**
-   * 门店信息列表
+   * 门店信息列表.
    */
   @SerializedName("business_list")
   private List businessList;
   /**
-   * 门店信息总数
+   * 门店信息总数.
    */
   @SerializedName("total_count")
   private Integer totalCount;
@@ -47,7 +49,7 @@ public class WxMpStoreListResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessage.java
index 8c784c66..b6f1eef5 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessage.java
@@ -1,14 +1,13 @@
 package me.chanjar.weixin.mp.bean.subscribe;
 
+import java.io.Serializable;
+
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
-import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-
 /**
  * @author Mklaus
  * @date 2018-01-22 下午12:18
@@ -78,5 +77,11 @@ public class WxMpSubscribeMessage {
 
     private String appid;
     private String pagePath;
+
+    /**
+     * 是否使用path,否则使用pagepath.
+     * 加入此字段是基于微信官方接口变化多端的考虑
+     */
+    private boolean usePath = false;
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxTagListUser.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxTagListUser.java
index f9697923..d6606cf1 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxTagListUser.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxTagListUser.java
@@ -1,13 +1,15 @@
 package me.chanjar.weixin.mp.bean.tag;
 
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-import java.util.List;
-
 /**
  * 
  * 获取标签下粉丝列表的结果对象
@@ -21,17 +23,17 @@ public class WxTagListUser implements Serializable {
   private static final long serialVersionUID = -4551768374200676112L;
 
   /**
-   * "count":2,这次获取的粉丝数量
+   * "count":2,这次获取的粉丝数量.
    */
   @SerializedName("count")
   private Integer count;
   /**
-   * "data" 粉丝列表
+   * "data" 粉丝列表.
    */
   @SerializedName("data")
   private WxTagListUserData data;
   /**
-   * "next_openid" 拉取列表最后一个用户的openid
+   * "next_openid" 拉取列表最后一个用户的openid.
    */
   @SerializedName("next_openid")
   private String nextOpenid;
@@ -46,7 +48,7 @@ public class WxTagListUser implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   @Data
@@ -54,14 +56,14 @@ public class WxTagListUser implements Serializable {
     private static final long serialVersionUID = -8584537400336245701L;
 
     /**
-     * openid 列表
+     * openid 列表.
      */
     @SerializedName("openid")
     private List openidList;
 
     @Override
     public String toString() {
-      return ToStringUtils.toSimpleString(this);
+      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
     }
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxUserTag.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxUserTag.java
index a54199ef..77251df2 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxUserTag.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxUserTag.java
@@ -1,14 +1,16 @@
 package me.chanjar.weixin.mp.bean.tag;
 
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.JsonParser;
 import com.google.gson.reflect.TypeToken;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-import java.util.List;
-
 /**
  * 
  *  用户标签对象
@@ -22,17 +24,17 @@ public class WxUserTag implements Serializable {
   private static final long serialVersionUID = -7722428695667031252L;
 
   /**
-   * id	标签id,由微信分配
+   * 标签id,由微信分配.
    */
   private Long id;
 
   /**
-   * name	标签名,UTF8编码
+   * 标签名,UTF8编码.
    */
   private String name;
 
   /**
-   * count 此标签下粉丝数
+   * 此标签下粉丝数.
    */
   private Integer count;
 
@@ -55,6 +57,6 @@ public class WxUserTag implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplate.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplate.java
index c9b12cdf..5ccd89fd 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplate.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplate.java
@@ -1,15 +1,17 @@
 package me.chanjar.weixin.mp.bean.template;
 
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.google.gson.JsonParser;
 import com.google.gson.annotations.SerializedName;
 import com.google.gson.reflect.TypeToken;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-import java.util.List;
-
 /**
  * 
  * 模板列表信息
@@ -24,37 +26,37 @@ public class WxMpTemplate implements Serializable {
   private static final long serialVersionUID = -7366474522571199372L;
 
   /**
-   * template_id
+   * template_id.
    * 模板ID
    */
   @SerializedName("template_id")
   private String templateId;
   /**
-   * title
+   * title.
    * 模板标题
    */
   @SerializedName("title")
   private String title;
   /**
-   * primary_industry
+   * primary_industry.
    * 模板所属行业的一级行业
    */
   @SerializedName("primary_industry")
   private String primaryIndustry;
   /**
-   * deputy_industry
+   * deputy_industry.
    * 模板所属行业的二级行业
    */
   @SerializedName("deputy_industry")
   private String deputyIndustry;
   /**
-   * content
+   * content.
    * 模板内容
    */
   @SerializedName("content")
   private String content;
   /**
-   * example
+   * example.
    * 模板示例
    */
   @SerializedName("example")
@@ -68,7 +70,7 @@ public class WxMpTemplate implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateIndustry.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateIndustry.java
index 363ddad7..40bfd18a 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateIndustry.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateIndustry.java
@@ -1,12 +1,14 @@
 package me.chanjar.weixin.mp.bean.template;
 
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-import java.io.Serializable;
-
 /**
  * @author miller
  */
@@ -31,7 +33,7 @@ public class WxMpTemplateIndustry implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   public String toJson() {
@@ -39,8 +41,7 @@ public class WxMpTemplateIndustry implements Serializable {
   }
 
   /**
-   * @author miller
-   *         官方文档中,创建和获取的数据结构不一样。所以采用冗余字段的方式,实现相应的接口
+   * 官方文档中,创建和获取的数据结构不一样。所以采用冗余字段的方式,实现相应的接口.
    */
   @Data
   public static class Industry implements Serializable {
@@ -64,7 +65,7 @@ public class WxMpTemplateIndustry implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringUtils.toSimpleString(this);
+      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
     }
 
   }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java
index a66dbc07..cb70893a 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java
@@ -77,6 +77,12 @@ public class WxMpTemplateMessage implements Serializable {
 
     private String appid;
     private String pagePath;
+
+    /**
+     * 是否使用path,否则使用pagepath.
+     * 加入此字段是基于微信官方接口变化多端的考虑
+     */
+    private boolean usePath = true;
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/TransferCustomerServiceBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/TransferCustomerServiceBuilder.java
index bc018e8f..8821608d 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/TransferCustomerServiceBuilder.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/TransferCustomerServiceBuilder.java
@@ -1,17 +1,19 @@
 package me.chanjar.weixin.mp.builder.outxml;
 
-import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTransferKefuMessage;
 import org.apache.commons.lang3.StringUtils;
 
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTransferKefuMessage;
+
 /**
  * 客服消息builder
  * 
- * 用法: WxMpKefuMessage m = WxMpXmlOutMessage.TRANSFER_CUSTOMER_SERVICE().content(...).toUser(...).build();
+ * 用法: WxMpXmlOutTransferKefuMessage m = WxMpXmlOutMessage.TRANSFER_CUSTOMER_SERVICE().kfAccount("").toUser("").build();
  * 
* * @author chanjarster */ -public final class TransferCustomerServiceBuilder extends BaseBuilder { +public final class TransferCustomerServiceBuilder + extends BaseBuilder { private String kfAccount; public TransferCustomerServiceBuilder kfAccount(String kf) { @@ -28,6 +30,7 @@ public final class TransferCustomerServiceBuilder extends BaseBuilder, JsonDeserializer { @Override @@ -59,7 +63,7 @@ public class WxMpMassNewsArticleGsonAdapter implements JsonSerializer, JsonDeserializer { @Override @@ -78,7 +81,7 @@ public class WxMpMaterialNewsArticleGsonAdapter implements JsonSerializer { @Override @@ -20,10 +23,15 @@ public class WxMpTemplateMessageGsonAdapter implements JsonSerializer com.github.binarywang weixin-java-parent - 3.1.0 + 3.2.0 weixin-java-open Weixin Java Tools - Open diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java index c2e19943..7c1b8465 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java @@ -1,6 +1,5 @@ package me.chanjar.weixin.open.api; -import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; @@ -41,7 +40,13 @@ public interface WxOpenComponentService { WxMpService getWxMpServiceByAppid(String appid); - WxMaService getWxMaServiceByAppid(String appid); + /** + * 获取指定appid的开放平台小程序服务(继承一般小程序服务能力) + * + * @param appid + * @return + */ + WxOpenMaService getWxMaServiceByAppid(String appid); WxOpenConfigStorage getWxOpenConfigStorage(); @@ -54,6 +59,13 @@ public interface WxOpenComponentService { */ String getPreAuthUrl(String redirectURI) throws WxErrorException; + /** + * authType 要授权的帐号类型:1则商户点击链接后,手机端仅展示公众号、2表示仅展示小程序,3表示公众号和小程序都展示。如果为未指定,则默认小程序和公众号都展示。第三方平台开发者可以使用本字段来控制授权的帐号类型。 + * bizAppid 指定授权唯一的小程序或公众号 + * 注:auth_type、biz_appid两个字段互斥。 + */ + String getPreAuthUrl(String redirectURI, String authType, String bizAppid) throws WxErrorException; + String route(WxOpenXmlMessage wxMessage) throws WxErrorException; /** diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenConfigStorage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenConfigStorage.java index b0d833b2..de9044ee 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenConfigStorage.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenConfigStorage.java @@ -1,6 +1,7 @@ package me.chanjar.weixin.open.api; import cn.binarywang.wx.miniapp.config.WxMaConfig; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; @@ -46,6 +47,8 @@ public interface WxOpenConfigStorage { String getHttpProxyPassword(); + ApacheHttpClientBuilder getApacheHttpClientBuilder(); + WxMpConfigStorage getWxMpConfigStorage(String appId); WxMaConfig getWxMaConfig(String appId); diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java new file mode 100644 index 00000000..2cb82ff7 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java @@ -0,0 +1,335 @@ +package me.chanjar.weixin.open.api; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.open.bean.ma.WxMaOpenCommitExtInfo; +import me.chanjar.weixin.open.bean.message.WxOpenMaSubmitAuditMessage; +import me.chanjar.weixin.open.bean.result.*; + +import java.io.File; +import java.util.List; +import java.util.Map; + +/** + *
+ *     微信开放平台代小程序实现服务能力
+ *     https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1489144594_DhNoV&token=&lang=zh_CN
+ * 
+ * + * @author yqx + * @date 2018/9/12 + */ +public interface WxOpenMaService extends WxMaService { + + /** + * 设置小程序服务器域名 + * + *
+   *     授权给第三方的小程序,其服务器域名只可以为第三方的服务器,当小程序通过第三方发布代码上线后,小程序原先自己配置的服务器域名将被删除,
+   *     只保留第三方平台的域名,所以第三方平台在代替小程序发布代码之前,需要调用接口为小程序添加第三方自身的域名。
+   *     提示:需要先将域名登记到第三方平台的小程序服务器域名中,才可以调用接口进行配置
+   * 
+ */ + String API_MODIFY_DOMAIN = "https://api.weixin.qq.com/wxa/modify_domain"; + + /** + * 设置小程序业务域名(仅供第三方代小程序调用) + *
+   *     授权给第三方的小程序,其业务域名只可以为第三方的服务器,当小程序通过第三方发布代码上线后,小程序原先自己配置的业务域名将被删除,
+   *     只保留第三方平台的域名,所以第三方平台在代替小程序发布代码之前,需要调用接口为小程序添加业务域名。
+   * 提示:
+   * 1、需要先将域名登记到第三方平台的小程序业务域名中,才可以调用接口进行配置。
+   * 2、为授权的小程序配置域名时支持配置子域名,例如第三方登记的业务域名如为qq.com,则可以直接将qq.com及其子域名(如xxx.qq.com)也配置到授权的小程序中。
+   * 
+ */ + String API_SET_WEBVIEW_DOMAIN = "https://api.weixin.qq.com/wxa/setwebviewdomain"; + + /** + * 获取帐号基本信息 + *
+   * GET请求
+   * 注意:需要使用1.3环节获取到的新创建小程序appid及authorization_code换取authorizer_refresh_token进而得到authorizer_access_token。
+   * 
+ */ + String API_GET_ACCOUNT_BASICINFO = "https://api.weixin.qq.com/cgi-bin/account/getaccountbasicinfo"; + + /** + * 绑定微信用户为小程序体验者 + */ + String API_BIND_TESTER = "https://api.weixin.qq.com/wxa/bind_tester"; + + + /** + * 解除绑定微信用户为小程序体验者 + */ + String API_UNBIND_TESTER = "https://api.weixin.qq.com/wxa/unbind_tester"; + + + /** + * 获取体验者列表 + */ + String API_GET_TESTERLIST = "https://api.weixin.qq.com/wxa/memberauth"; + + /** + * 以下接口为三方平台代小程序实现的代码管理功能 + *

+ * https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1489140610_Uavc4&token=fe774228c66725425675810097f9e48d0737a4bf&lang=zh_CN + *

+ */ + + /** + * 1. 为授权的小程序帐号上传小程序代码 + */ + String API_CODE_COMMIT = "https://api.weixin.qq.com/wxa/commit"; + + /** + * 2. 获取体验小程序的体验二维码 + */ + String API_TEST_QRCODE = "https://api.weixin.qq.com/wxa/get_qrcode"; + + /** + * 3. 获取授权小程序帐号的可选类目 + */ + String API_GET_CATEGORY = "https://api.weixin.qq.com/wxa/get_category"; + + /** + * 4. 获取小程序的第三方提交代码的页面配置(仅供第三方开发者代小程序调用) + */ + String API_GET_PAGE = "https://api.weixin.qq.com/wxa/get_page"; + + /** + * 5. 将第三方提交的代码包提交审核(仅供第三方开发者代小程序调用) + */ + String API_SUBMIT_AUDIT = "https://api.weixin.qq.com/wxa/submit_audit"; + + /** + * 7. 查询某个指定版本的审核状态(仅供第三方代小程序调用) + */ + String API_GET_AUDIT_STATUS = "https://api.weixin.qq.com/wxa/get_auditstatus"; + + /** + * 8. 查询最新一次提交的审核状态(仅供第三方代小程序调用) + */ + String API_GET_LATEST_AUDIT_STATUS = "https://api.weixin.qq.com/wxa/get_latest_auditstatus"; + + /** + * 9. 发布已通过审核的小程序(仅供第三方代小程序调用) + */ + String API_RELEASE = "https://api.weixin.qq.com/wxa/release"; + + /** + * 10. 修改小程序线上代码的可见状态(仅供第三方代小程序调用) + */ + String API_CHANGE_VISITSTATUS = "https://api.weixin.qq.com/wxa/change_visitstatus"; + + /** + * 11.小程序版本回退(仅供第三方代小程序调用) + */ + String API_REVERT_CODE_RELEASE = "https://api.weixin.qq.com/wxa/revertcoderelease"; + + /** + * 12.查询当前设置的最低基础库版本及各版本用户占比 (仅供第三方代小程序调用) + */ + String API_GET_WEAPP_SUPPORT_VERSION = "https://api.weixin.qq.com/cgi-bin/wxopen/getweappsupportversion"; + + /** + * 13.设置最低基础库版本(仅供第三方代小程序调用) + */ + String API_SET_WEAPP_SUPPORT_VERSION = "https://api.weixin.qq.com/cgi-bin/wxopen/setweappsupportversion"; + + /** + * 14.设置小程序“扫普通链接二维码打开小程序”能力 + *

+ * TODO 暂时不实现 + *

+ */ + + /** + * 15.小程序审核撤回 + *

+ * 单个帐号每天审核撤回次数最多不超过1次,一个月不超过10次。 + *

+ */ + String API_UNDO_CODE_AUDIT = "https://api.weixin.qq.com/wxa/undocodeaudit"; + + /** + * 16.1 小程序分阶段发布-分阶段发布接口 + */ + String API_GRAY_RELEASE = "https://api.weixin.qq.com/wxa/grayrelease"; + + /** + * 16.2 小程序分阶段发布-取消分阶段发布 + */ + String API_REVERT_GRAY_RELEASE = "https://api.weixin.qq.com/wxa/revertgrayrelease"; + + /** + * 16.3 小程序分阶段发布-查询当前分阶段发布详情 + */ + String API_GET_GRAY_RELEASE_PLAN = "https://api.weixin.qq.com/wxa/getgrayreleaseplan"; + + + /** + * 获得小程序的域名配置信息 + * + * @return + */ + WxOpenMaDomainResult getDomain() throws WxErrorException; + + /** + * 修改域名 + * + * @param action delete删除, set覆盖, get获取 + * @param requestdomainList + * @param wsrequestdomainList + * @param uploaddomainList + * @param downloaddomainList + * @return + * @throws WxErrorException + */ + WxOpenMaDomainResult modifyDomain(String action, List requestdomainList, List wsrequestdomainList, List uploaddomainList, List downloaddomainList) throws WxErrorException; + + /** + * 获取小程序的业务域名 + * + * @return 直接返回字符串 + */ + String getWebViewDomain() throws WxErrorException; + + /** + * 设置小程序的业务域名 + * + * @param action add添加, delete删除, set覆盖 + * @param domainList + * @return 直接返回字符串 + */ + String setWebViewDomain(String action, List domainList) throws WxErrorException; + + /** + * 获取小程序的信息 + * + * @return + * @throws WxErrorException + */ + String getAccountBasicInfo() throws WxErrorException; + + /** + * 绑定小程序体验者 + * + * @param wechatid 体验者微信号(不是openid) + * @return + * @throws WxErrorException + */ + String bindTester(String wechatid) throws WxErrorException; + + /** + * 解除绑定小程序体验者 + * + * @param wechatid 体验者微信号(不是openid) + * @return + * @throws WxErrorException + */ + String unbindTester(String wechatid) throws WxErrorException; + + /** + * 获得体验者列表 + * + * @return + * @throws WxErrorException + */ + WxOpenMaTesterListResult getTesterList() throws WxErrorException; + + /** + * 1、为授权的小程序帐号上传小程序代码 + * + * @param templateId 代码模板ID + * @param userVersion 用户定义版本 + * @param userDesc 用户定义版本描述 + * @param extInfo 第三方自定义的配置 + * @return + * @throws WxErrorException + */ + String codeCommit(Long templateId, String userVersion, String userDesc, WxMaOpenCommitExtInfo extInfo) throws WxErrorException; + + /** + * 获取体验小程序的体验二维码 + * + * @param pagePath + * @param params + * @return + */ + File getTestQrcode(String pagePath, Map params) throws WxErrorException; + + /** + * 获取授权小程序帐号的可选类目 + *

+ * 注意:该接口可获取已设置的二级类目及用于代码审核的可选三级类目。 + *

+ * + * @return WxOpenMaCategoryListResult + * @throws WxErrorException + */ + WxOpenMaCategoryListResult getCategoryList() throws WxErrorException; + + /** + * 获取小程序的第三方提交代码的页面配置(仅供第三方开发者代小程序调用) + * + * @return + * @throws WxErrorException + */ + WxOpenMaPageListResult getPageList() throws WxErrorException; + + /** + * 将第三方提交的代码包提交审核(仅供第三方开发者代小程序调用) + * + * @param submitAuditMessage + * @return + * @throws WxErrorException + */ + WxOpenMaSubmitAuditResult submitAudit(WxOpenMaSubmitAuditMessage submitAuditMessage) throws WxErrorException; + + /** + * 查询某个指定版本的审核状态(仅供第三方代小程序调用) + * + * @param auditid + * @return + * @throws WxErrorException + */ + String getAuditStatus(Long auditid) throws WxErrorException; + + /** + * 查询最新一次提交的审核状态(仅供第三方代小程序调用) + * + * @param auditid + * @return + * @throws WxErrorException + */ + String getLatestAuditStatus(Long auditid) throws WxErrorException; + + /** + * 发布已通过审核的小程序(仅供第三方代小程序调用) + * + * @return + * @throws WxErrorException + */ + String releaesAudited() throws WxErrorException; + + /** + * 11. 小程序版本回退(仅供第三方代小程序调用) + * + * @return + * @throws WxErrorException + */ + String revertCodeReleaes() throws WxErrorException; + + /** + * 15. 小程序审核撤回 + *

+ * 单个帐号每天审核撤回次数最多不超过1次,一个月不超过10次。 + *

+ * + * @return + * @throws WxErrorException + */ + String undoCodeAudit() throws WxErrorException; + +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java index 05f3df11..2fd53dc5 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java @@ -1,6 +1,5 @@ package me.chanjar.weixin.open.api.impl; -import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -14,6 +13,7 @@ import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; import me.chanjar.weixin.open.api.WxOpenComponentService; import me.chanjar.weixin.open.api.WxOpenConfigStorage; +import me.chanjar.weixin.open.api.WxOpenMaService; import me.chanjar.weixin.open.api.WxOpenService; import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; @@ -37,7 +37,7 @@ import java.util.Map; */ public class WxOpenComponentServiceImpl implements WxOpenComponentService { private static final JsonParser JSON_PARSER = new JsonParser(); - private static final Map WX_OPEN_MA_SERVICE_MAP = new Hashtable<>(); + private static final Map WX_OPEN_MA_SERVICE_MAP = new Hashtable<>(); private static final Map WX_OPEN_MP_SERVICE_MAP = new Hashtable<>(); protected final Logger log = LoggerFactory.getLogger(this.getClass()); @@ -64,18 +64,18 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService { } @Override - public WxMaService getWxMaServiceByAppid(String appId) { - WxMaService wxMaService = WX_OPEN_MA_SERVICE_MAP.get(appId); - if (wxMaService == null) { + public WxOpenMaService getWxMaServiceByAppid(String appId) { + WxOpenMaService wxOpenMaService = WX_OPEN_MA_SERVICE_MAP.get(appId); + if (wxOpenMaService == null) { synchronized (WX_OPEN_MA_SERVICE_MAP) { - wxMaService = WX_OPEN_MA_SERVICE_MAP.get(appId); - if (wxMaService == null) { - wxMaService = new WxOpenMaServiceImpl(this, appId, getWxOpenConfigStorage().getWxMaConfig(appId)); - WX_OPEN_MA_SERVICE_MAP.put(appId, wxMaService); + wxOpenMaService = WX_OPEN_MA_SERVICE_MAP.get(appId); + if (wxOpenMaService == null) { + wxOpenMaService = new WxOpenMaServiceImpl(this, appId, getWxOpenConfigStorage().getWxMaConfig(appId)); + WX_OPEN_MA_SERVICE_MAP.put(appId, wxOpenMaService); } } } - return wxMaService; + return wxOpenMaService; } public WxOpenService getWxOpenService() { @@ -148,6 +148,7 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService { private String get(String uri) throws WxErrorException { return get(uri, "component_access_token"); } + private String get(String uri, String accessTokenKey) throws WxErrorException { String componentAccessToken = getComponentAccessToken(false); String uriWithComponentAccessToken = uri + (uri.contains("?") ? "&" : "?") + accessTokenKey + "=" + componentAccessToken; @@ -177,14 +178,31 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService { @Override public String getPreAuthUrl(String redirectURI) throws WxErrorException { + return getPreAuthUrl(redirectURI, null, null); + } + @Override + public String getPreAuthUrl(String redirectURI, String authType, String bizAppid) throws WxErrorException { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId()); String responseContent = post(API_CREATE_PREAUTHCODE_URL, jsonObject.toString()); jsonObject = WxGsonBuilder.create().fromJson(responseContent, JsonObject.class); - return String.format(COMPONENT_LOGIN_PAGE_URL, getWxOpenConfigStorage().getComponentAppId(), jsonObject.get("pre_auth_code").getAsString(), URIUtil.encodeURIComponent(redirectURI)); + + StringBuilder preAuthUrl = new StringBuilder(String.format(COMPONENT_LOGIN_PAGE_URL, + getWxOpenConfigStorage().getComponentAppId(), + jsonObject.get("pre_auth_code").getAsString(), + URIUtil.encodeURIComponent(redirectURI))); + if (StringUtils.isNotEmpty(authType)) { + preAuthUrl.append("&auth_type=").append(authType); + } + if (StringUtils.isNotEmpty(bizAppid)) { + preAuthUrl.append("&biz_appid=").append(bizAppid); + } + + return preAuthUrl.toString(); } + @Override public String route(final WxOpenXmlMessage wxMessage) throws WxErrorException { if (wxMessage == null) { diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java index 56e1d9a1..a340be81 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java @@ -1,21 +1,23 @@ package me.chanjar.weixin.open.api.impl; +import java.io.File; +import java.util.Hashtable; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + import cn.binarywang.wx.miniapp.config.WxMaConfig; import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.open.api.WxOpenConfigStorage; import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; -import java.io.File; -import java.util.Hashtable; -import java.util.Map; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - /** * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 * @@ -34,6 +36,7 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { private int httpProxyPort; private String httpProxyUsername; private String httpProxyPassword; + private ApacheHttpClientBuilder apacheHttpClientBuilder; private Map authorizerRefreshTokens = new Hashtable<>(); private Map authorizerAccessTokens = new Hashtable<>(); @@ -146,6 +149,15 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { this.httpProxyPassword = httpProxyPassword; } + @Override + public ApacheHttpClientBuilder getApacheHttpClientBuilder() { + return apacheHttpClientBuilder; + } + + public ApacheHttpClientBuilder setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { + return this.apacheHttpClientBuilder = apacheHttpClientBuilder; + } + @Override public WxMpConfigStorage getWxMpConfigStorage(String appId) { return new WxOpenInnerConfigStorage(this, appId); @@ -438,7 +450,7 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { @Override public String toString() { - return ToStringUtils.toSimpleString(this); + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } @Override @@ -448,7 +460,7 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { @Override public ApacheHttpClientBuilder getApacheHttpClientBuilder() { - return null; + return wxOpenConfigStorage.getApacheHttpClientBuilder(); } diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java index acadd7e6..2cdfcc45 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java @@ -1,16 +1,34 @@ package me.chanjar.weixin.open.api.impl; -import cn.binarywang.wx.miniapp.api.WxMaUserService; import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.open.api.WxOpenComponentService; +import me.chanjar.weixin.open.api.WxOpenMaService; +import me.chanjar.weixin.open.bean.ma.WxMaOpenCommitExtInfo; +import me.chanjar.weixin.open.bean.ma.WxMaQrcodeParam; +import me.chanjar.weixin.open.bean.message.WxOpenMaSubmitAuditMessage; +import me.chanjar.weixin.open.bean.result.*; +import me.chanjar.weixin.open.util.requestexecuter.ma.MaQrCodeRequestExecutor; + +import java.io.File; +import java.util.List; +import java.util.Map; /** * @author 007 + *
+ *     增加开放平台代小程序管理服务能力
+ *     说明:这里让这个服务公开便于调用者模拟本地测试服务
+ * 
+ * @author yqx + * @date 2018-09-12 */ -/* package */ class WxOpenMaServiceImpl extends WxMaServiceImpl { +public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaService { private WxOpenComponentService wxOpenComponentService; private WxMaConfig wxMaConfig; private String appId; @@ -26,6 +44,7 @@ import me.chanjar.weixin.open.api.WxOpenComponentService; public WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException { return wxOpenComponentService.miniappJscode2Session(appId, jsCode); } + @Override public WxMaConfig getWxMaConfig() { return wxMaConfig; @@ -35,4 +54,293 @@ import me.chanjar.weixin.open.api.WxOpenComponentService; public String getAccessToken(boolean forceRefresh) throws WxErrorException { return wxOpenComponentService.getAuthorizerAccessToken(appId, forceRefresh); } + + /** + * 获得小程序的域名配置信息 + * + * @return + */ + @Override + public WxOpenMaDomainResult getDomain() throws WxErrorException { + return modifyDomain("get", null, null, null, null); + } + + /** + * 修改服务器域名 + * + * @param action delete删除, set覆盖, get获取 + * @param requestdomainList + * @param wsrequestdomainList + * @param uploaddomainList + * @param downloaddomainList + * @return + * @throws WxErrorException + */ + public WxOpenMaDomainResult modifyDomain(String action, List requestdomainList, List wsrequestdomainList, List uploaddomainList, List downloaddomainList) throws WxErrorException { + +// if (!"get".equals(action) && (requestdomainList == null || wsrequestdomainList == null || uploaddomainList == null || downloaddomainList == null)) { +// throw new WxErrorException(WxError.builder().errorCode(44004).errorMsg("域名参数不能为空").build()); +// } + JsonObject requestJson = new JsonObject(); + requestJson.addProperty("action", action); + if (!"get".equals(action)) { + requestJson.add("requestdomain", toJsonArray(requestdomainList)); + requestJson.add("wsrequestdomain", toJsonArray(wsrequestdomainList)); + requestJson.add("uploaddomain", toJsonArray(uploaddomainList)); + requestJson.add("downloaddomain", toJsonArray(downloaddomainList)); + } + String response = post(API_MODIFY_DOMAIN, GSON.toJson(requestJson)); + return WxMaGsonBuilder.create().fromJson(response, WxOpenMaDomainResult.class); + } + + /** + * 获取小程序的业务域名 + * + * @return + */ + @Override + public String getWebViewDomain() throws WxErrorException { + return setWebViewDomain("get", null); + } + + /** + * 设置小程序的业务域名 + * + * @param action add添加, delete删除, set覆盖 + * @param domainList + * @return + */ + @Override + public String setWebViewDomain(String action, List domainList) throws WxErrorException { + JsonObject requestJson = new JsonObject(); + requestJson.addProperty("action", action); + if (!"get".equals(action)) { + requestJson.add("webviewdomain", toJsonArray(domainList)); + } + String response = post(API_SET_WEBVIEW_DOMAIN, GSON.toJson(requestJson)); + //TODO 转化为对象返回 + return response; + } + + /** + * 获取小程序的信息,GET请求 + *
+   *     注意:这里不能直接用小程序的access_token
+   *     //TODO 待调整
+   * 
+ * + * @return + * @throws WxErrorException + */ + @Override + public String getAccountBasicInfo() throws WxErrorException { + String response = get(API_GET_ACCOUNT_BASICINFO, ""); + return response; + } + + /** + * 绑定小程序体验者 + * + * @param wechatid 体验者微信号(不是openid) + * @return + * @throws WxErrorException + */ + @Override + public String bindTester(String wechatid) throws WxErrorException { + JsonObject paramJson = new JsonObject(); + paramJson.addProperty("wechatid", wechatid); + String response = post(API_BIND_TESTER, GSON.toJson(paramJson)); + return response; + } + + /** + * 解除绑定小程序体验者 + * + * @param wechatid 体验者微信号(不是openid) + * @return + * @throws WxErrorException + */ + @Override + public String unbindTester(String wechatid) throws WxErrorException { + JsonObject paramJson = new JsonObject(); + paramJson.addProperty("wechatid", wechatid); + String response = post(API_UNBIND_TESTER, GSON.toJson(paramJson)); + return response; + } + + /** + * 获得体验者列表 + * + * @return + * @throws WxErrorException + */ + @Override + public WxOpenMaTesterListResult getTesterList() throws WxErrorException { + JsonObject paramJson = new JsonObject(); + paramJson.addProperty("action", "get_experiencer"); + String response = post(API_GET_TESTERLIST, GSON.toJson(paramJson)); + return WxMaGsonBuilder.create().fromJson(response, WxOpenMaTesterListResult.class); + } + + /** + * 1、为授权的小程序帐号上传小程序代码 + * + * @param templateId 代码模板ID + * @param userVersion 用户定义版本 + * @param userDesc 用户定义版本描述 + * @param extInfo 第三方自定义的配置 + * @return + * @throws WxErrorException + */ + @Override + public String codeCommit(Long templateId, String userVersion, String userDesc, WxMaOpenCommitExtInfo extInfo) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("template_id", templateId); + params.addProperty("user_version", userVersion); + params.addProperty("user_desc", userDesc); + //注意:ext_json必须是字符串类型 + params.addProperty("ext_json", GSON.toJson(extInfo)); + String response = post(API_CODE_COMMIT, GSON.toJson(params)); + return response; + } + + /** + * 获取体验小程序的体验二维码 + * + * @param pagePath + * @param params + * @return + */ + @Override + public File getTestQrcode(String pagePath, Map params) throws WxErrorException { + WxMaQrcodeParam qrcodeParam = WxMaQrcodeParam.create(pagePath); + qrcodeParam.addPageParam(params); + return execute(MaQrCodeRequestExecutor.create(getRequestHttp()), API_TEST_QRCODE, qrcodeParam); + } + + /** + * 获取授权小程序帐号的可选类目 + *

+ * 注意:该接口可获取已设置的二级类目及用于代码审核的可选三级类目。 + *

+ * + * @return WxOpenMaCategoryListResult + * @throws WxErrorException + */ + @Override + public WxOpenMaCategoryListResult getCategoryList() throws WxErrorException { + String response = get(API_GET_CATEGORY, null); + return WxMaGsonBuilder.create().fromJson(response, WxOpenMaCategoryListResult.class); + } + + /** + * 获取小程序的第三方提交代码的页面配置(仅供第三方开发者代小程序调用) + * + * @return + * @throws WxErrorException + */ + @Override + public WxOpenMaPageListResult getPageList() throws WxErrorException { + String response = get(API_GET_PAGE, null); + return WxMaGsonBuilder.create().fromJson(response, WxOpenMaPageListResult.class); + } + + /** + * 将第三方提交的代码包提交审核(仅供第三方开发者代小程序调用) + * + * @param submitAuditMessage + * @return + * @throws WxErrorException + */ + public WxOpenMaSubmitAuditResult submitAudit(WxOpenMaSubmitAuditMessage submitAuditMessage) throws WxErrorException { + String response = post(API_SUBMIT_AUDIT, GSON.toJson(submitAuditMessage)); + return WxMaGsonBuilder.create().fromJson(response, WxOpenMaSubmitAuditResult.class); + } + + /** + * 7. 查询某个指定版本的审核状态(仅供第三方代小程序调用) + * + * @param auditid + * @return + * @throws WxErrorException + */ + @Override + public String getAuditStatus(Long auditid) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("auditid", auditid); + String response = post(API_GET_AUDIT_STATUS, GSON.toJson(params)); + return response; + } + + /** + * 8. 查询最新一次提交的审核状态(仅供第三方代小程序调用) + * + * @param auditid + * @return + * @throws WxErrorException + */ + @Override + public String getLatestAuditStatus(Long auditid) throws WxErrorException { + String response = get(API_GET_LATEST_AUDIT_STATUS, null); + return response; + } + + /** + * 9. 发布已通过审核的小程序(仅供第三方代小程序调用) + *

+ * 请填写空的数据包,POST的json数据包为空即可。 + *

+ * + * @return + * @throws WxErrorException + */ + @Override + public String releaesAudited() throws WxErrorException { + JsonObject params = new JsonObject(); + String response = post(API_RELEASE, GSON.toJson(params)); + return response; + } + + /** + * 11. 小程序版本回退(仅供第三方代小程序调用) + * + * @return + * @throws WxErrorException + */ + @Override + public String revertCodeReleaes() throws WxErrorException { + String response = get(API_REVERT_CODE_RELEASE, null); + return response; + } + + /** + * 15. 小程序审核撤回 + *

+ * 单个帐号每天审核撤回次数最多不超过1次,一个月不超过10次。 + *

+ * + * @return + * @throws WxErrorException + */ + @Override + public String undoCodeAudit() throws WxErrorException { + String response = get(API_UNDO_CODE_AUDIT, null); + return response; + } + + /** + * 将字符串对象转化为GsonArray对象 + * + * @param strList + * @return + */ + private JsonArray toJsonArray(List strList) { + JsonArray jsonArray = new JsonArray(); + if (strList != null && !strList.isEmpty()) { + for (String str : strList) { + jsonArray.add(str); + } + } + return jsonArray; + } } diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceApacheHttpClientImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceApacheHttpClientImpl.java index e428af56..d9b7b495 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceApacheHttpClientImpl.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceApacheHttpClientImpl.java @@ -4,7 +4,9 @@ import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; +import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.open.api.WxOpenConfigStorage; import org.apache.http.HttpHost; import org.apache.http.impl.client.CloseableHttpClient; @@ -21,14 +23,22 @@ public class WxOpenServiceApacheHttpClientImpl extends WxOpenServiceAbstractImpl @Override public void initHttp() { WxOpenConfigStorage configStorage = this.getWxOpenConfigStorage(); - if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { - this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort()); + ApacheHttpClientBuilder apacheHttpClientBuilder = configStorage.getApacheHttpClientBuilder(); + if (null == apacheHttpClientBuilder) { + apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get(); } - this.httpClient = DefaultApacheHttpClientBuilder.get() - .httpProxyHost(configStorage.getHttpProxyHost()) + + apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost()) .httpProxyPort(configStorage.getHttpProxyPort()) .httpProxyUsername(configStorage.getHttpProxyUsername()) - .httpProxyPassword(configStorage.getHttpProxyPassword()).build(); + .httpProxyPassword(configStorage.getHttpProxyPassword()); + + if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { + this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort()); + } + + this.httpClient = apacheHttpClientBuilder.build(); + } @Override diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenCommitExtInfo.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenCommitExtInfo.java new file mode 100644 index 00000000..c38867ba --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenCommitExtInfo.java @@ -0,0 +1,96 @@ +package me.chanjar.weixin.open.bean.ma; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 微信小程序三方平台代上传代码提交额外信息对象 + *

+ * 如果代码中已经有配置,则配置的合并规则为:除了pages和tabBar.list直接覆盖原配置,其他都为插入或同级覆盖。 + *

+ * + * @author yqx + * @date 2018/9/13 + */ +@Data +public class WxMaOpenCommitExtInfo implements Serializable { + + WxMaOpenCommitExtInfo() { + + } + + /** + * 授权小程序Appid,可填入商户小程序AppID,以区分不同商户 + */ + private String extAppid; + + @SerializedName("ext") + private Map extMap; + + @SerializedName("extPages") + private Map extPages; + + /** + * 页面路径列表(和app.json结构一致) + */ + @SerializedName("pages") + private List pageList; + + @SerializedName("window") + private WxMaOpenWindow window; + + @SerializedName("networkTimeout") + private WxMaOpenNetworkTimeout networkTimeout; + + @SerializedName("tabBar") + private WxMaOpenTabBar tabBar; + + /** + * 添加扩展项 + * + * @param key + * @param value + */ + public void addExt(String key, String value) { + if (extMap == null) + extMap = new HashMap<>(); + if (StringUtils.isNoneBlank(key, value)) + extMap.put(key, value); + } + + /** + * 添加扩展页面 + * + * @param pagePath + * @param page + */ + public void addExtPage(String pagePath, WxMaOpenPage page) { + if (extPages == null) + extPages = new HashMap<>(); + if (StringUtils.isNotBlank(pagePath) && page != null) + extPages.put(pagePath, page); + } + + /** + * 添加页面 + * + * @param pagePath + */ + public void addPage(String pagePath) { + if (pageList == null) + pageList = new ArrayList<>(); + if (StringUtils.isNotBlank(pagePath)) + pageList.add(pagePath); + } + + public static WxMaOpenCommitExtInfo INSTANCE() { + return new WxMaOpenCommitExtInfo(); + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenNetworkTimeout.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenNetworkTimeout.java new file mode 100644 index 00000000..9717f42a --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenNetworkTimeout.java @@ -0,0 +1,21 @@ +package me.chanjar.weixin.open.bean.ma; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author yqx + * @date 2018/9/13 + */ +@Data +public class WxMaOpenNetworkTimeout implements Serializable { + + private Integer request; + + private Integer connectSocket; + + private Integer uploadFile; + + private Integer downloadFile; +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenPage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenPage.java new file mode 100644 index 00000000..ca63fc3d --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenPage.java @@ -0,0 +1,22 @@ +package me.chanjar.weixin.open.bean.ma; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author yqx + * @date 2018/9/13 + */ +@Data +public class WxMaOpenPage implements Serializable { + private String navigationBarBackgroundColor; + private String navigationBarTextStyle; + private String navigationBarTitleText; + private String backgroundColor; + private String backgroundTextStyle; + private Boolean enablePullDownRefresh; + private Integer onReachBottomDistance; + private Boolean disableScroll; + +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenTab.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenTab.java new file mode 100644 index 00000000..68d7cacb --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenTab.java @@ -0,0 +1,21 @@ +package me.chanjar.weixin.open.bean.ma; + +import lombok.Data; +import lombok.NonNull; + +import java.io.Serializable; + +/** + * @author yqx + * @date 2018/9/13 + */ +@Data +public class WxMaOpenTab implements Serializable { + @NonNull + private String pagePath; + + @NonNull + private String text; + private String iconPath; + private String selectedIconPath; +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenTabBar.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenTabBar.java new file mode 100644 index 00000000..6245c033 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenTabBar.java @@ -0,0 +1,49 @@ +package me.chanjar.weixin.open.bean.ma; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * tabBar对象 + * + * @author yqx + * @date 2018/9/13 + */ +@Data +@NoArgsConstructor +public class WxMaOpenTabBar implements Serializable { + @NonNull + private String color; + + @NonNull + private String selectedColor; + + @NonNull + private String backgroundColor; + + private String borderStyle; + + @NonNull + @SerializedName("list") + private List tabList; + + private String position; + + /** + * 添加tab + * + * @param text + * @param pagePath + */ + public void addTab(String text, String pagePath) { + if (tabList == null) + tabList = new ArrayList<>(); + tabList.add(new WxMaOpenTab(pagePath, text)); + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenWindow.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenWindow.java new file mode 100644 index 00000000..4848f8c7 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenWindow.java @@ -0,0 +1,34 @@ +package me.chanjar.weixin.open.bean.ma; + +import lombok.Data; + +import java.io.Serializable; + +/** + * window对象 + * + * @author yqx + * @date 2018/9/13 + */ +@Data +public class WxMaOpenWindow implements Serializable { + private String navigationBarBackgroundColor; + + private String navigationBarTextStyle; + + private String navigationBarTitleText; + + private String navigationStyle; + + private String backgroundColor; + + private String backgroundTextStyle; + + private String backgroundColorTop; + + private String backgroundColorBottom; + + private Boolean enablePullDownRefresh; + + private Integer onReachBottomDistance; +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaQrcodeParam.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaQrcodeParam.java new file mode 100644 index 00000000..2dafa037 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaQrcodeParam.java @@ -0,0 +1,86 @@ +package me.chanjar.weixin.open.bean.ma; + +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * 微信小程序体验二维码参数 + * + * @author yqx + * @date 2018/9/13 + */ +@Data +public class WxMaQrcodeParam { + + WxMaQrcodeParam() { + + } + + /** + * 页面路径 + */ + private String pagePath; + + /** + * 页面参数 + */ + private Map pageParams; + + /** + * 添加页面参数 + * + * @param key + * @param value + */ + public WxMaQrcodeParam addPageParam(String key, String value) { + if (StringUtils.isNoneBlank(key, value)) { + if (pageParams == null) + pageParams = new HashMap<>(); + pageParams.put(key, value); + } + return this; + } + + /** + * 添加页面参数 + * + * @param params + * @return + */ + public WxMaQrcodeParam addPageParam(Map params) { + if (params != null) { + if (pageParams == null) + pageParams = new HashMap<>(); + pageParams.putAll(params); + } + return this; + } + + /** + * 组装完整的页面请求路径(带参数) + * + * @return + */ + public String getRequestPath() { + if (StringUtils.isNotBlank(getPagePath()) && getPageParams() != null && !getPageParams().isEmpty()) { + Set keys = getPageParams().keySet(); + StringBuilder sb = new StringBuilder(); + for (String key : keys) { + sb.append("&").append(key).append("=").append(getPageParams().get(key)); + } + return pagePath + "?" + sb.substring(1); + } else { + return pagePath; + } + } + + public static WxMaQrcodeParam create(String pagePath) { + WxMaQrcodeParam instance = new WxMaQrcodeParam(); + instance.setPagePath(pagePath); + return instance; + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaCategory.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaCategory.java new file mode 100644 index 00000000..88ca63ae --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaCategory.java @@ -0,0 +1,40 @@ +package me.chanjar.weixin.open.bean.ma; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.io.Serializable; + +/** + * 微信小程序分类目录 + * + * @author yqx + * @date 2018/9/13 + */ +@Data +public class WxOpenMaCategory implements Serializable { + + @SerializedName("first_class") + private String firstClass; + + @SerializedName("second_class") + private String secondClass; + + @SerializedName("third_class") + private String thirdClass; + + @SerializedName("first_id") + private Integer firstId; + + @SerializedName("second_id") + private Integer secondId; + + @SerializedName("third_id") + private Integer thirdId; + + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaMember.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaMember.java new file mode 100644 index 00000000..dc939373 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaMember.java @@ -0,0 +1,19 @@ +package me.chanjar.weixin.open.bean.ma; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 微信开放平台小程序成员对象 + * + * @author yqx + * @date 2018/9/12 + */ +@Data +public class WxOpenMaMember implements Serializable { + /** + * 人员对应的唯一字符串 + */ + private String userstr; +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaSubmitAudit.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaSubmitAudit.java new file mode 100644 index 00000000..9c9e7122 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaSubmitAudit.java @@ -0,0 +1,60 @@ +package me.chanjar.weixin.open.bean.ma; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 三方平台提交小程序代码审核 + * + * @author yqx + * @date 2018/9/13 + */ +@Data +public class WxOpenMaSubmitAudit implements Serializable { + + + /** + * 小程序的页面,可通过“获取小程序的第三方提交代码的页面配置”接口获得 + */ + @SerializedName("address") + private String pagePath; + + /** + * 小程序的标签,多个标签用空格分隔,标签不能多于10个,标签长度不超过20 + */ + @SerializedName("tag") + private String tag; + + /** + * 类目名称,可通过“获取授权小程序帐号的可选类目”接口获得 + */ + @SerializedName("first_class") + private String firstClass; + + @SerializedName("second_class") + private String secondClass; + + @SerializedName("third_class") + private String thirdClass; + + /** + * 类目的ID,可通过“获取授权小程序帐号的可选类目”接口获得 + */ + @SerializedName("first_id") + private Integer firstId; + + @SerializedName("second_id") + private Integer secondId; + + @SerializedName("third_id") + private Integer thirdId; + + /** + * 小程序页面的标题,标题长度不超过32 + */ + @SerializedName("title") + private String title; + +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenMaSubmitAuditMessage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenMaSubmitAuditMessage.java new file mode 100644 index 00000000..a8d806b3 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenMaSubmitAuditMessage.java @@ -0,0 +1,21 @@ +package me.chanjar.weixin.open.bean.message; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.open.bean.ma.WxOpenMaSubmitAudit; + +import java.io.Serializable; +import java.util.List; + +/** + * 微信小程序代码包提交审核(仅供第三方开发者代小程序调用) + * + * @author yqx + * @date 2018/9/13 + */ +@Data +public class WxOpenMaSubmitAuditMessage implements Serializable { + + @SerializedName("item_list") + private List itemList; +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java index ac42696a..f3819452 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java @@ -1,25 +1,28 @@ package me.chanjar.weixin.open.bean.message; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; + +import org.apache.commons.io.IOUtils; + import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamConverter; import lombok.Data; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; import me.chanjar.weixin.open.api.WxOpenConfigStorage; import me.chanjar.weixin.open.util.WxOpenCryptUtil; import me.chanjar.weixin.open.util.xml.XStreamTransformer; -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; /** * @author 007 */ -@XStreamAlias("xml") @Data +@Slf4j +@XStreamAlias("xml") public class WxOpenXmlMessage implements Serializable { private static final long serialVersionUID = -5641769554709507771L; @@ -78,30 +81,26 @@ public class WxOpenXmlMessage implements Serializable { * @param nonce 随机串 * @param msgSignature 签名串 */ - public static WxOpenXmlMessage fromEncryptedXml(String encryptedXml, - WxOpenConfigStorage wxOpenConfigStorage, String timestamp, String nonce, - String msgSignature) { + public static WxOpenXmlMessage fromEncryptedXml(String encryptedXml, WxOpenConfigStorage wxOpenConfigStorage, + String timestamp, String nonce, String msgSignature) { WxOpenCryptUtil cryptUtil = new WxOpenCryptUtil(wxOpenConfigStorage); - String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, - encryptedXml); + String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml); + log.debug("解密后的原始xml消息内容:{}", plainText); return fromXml(plainText); } - public static WxMpXmlMessage fromEncryptedMpXml(String encryptedXml, - WxOpenConfigStorage wxOpenConfigStorage, String timestamp, String nonce, - String msgSignature) { + public static WxMpXmlMessage fromEncryptedMpXml(String encryptedXml, WxOpenConfigStorage wxOpenConfigStorage, + String timestamp, String nonce, String msgSignature) { WxOpenCryptUtil cryptUtil = new WxOpenCryptUtil(wxOpenConfigStorage); - String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, - encryptedXml); + String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml); return WxMpXmlMessage.fromXml(plainText); } - public static WxOpenXmlMessage fromEncryptedXml(InputStream is, - WxOpenConfigStorage wxOpenConfigStorage, String timestamp, String nonce, - String msgSignature) { + public static WxOpenXmlMessage fromEncryptedXml(InputStream is, WxOpenConfigStorage wxOpenConfigStorage, + String timestamp, String nonce, String msgSignature) { try { - return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxOpenConfigStorage, - timestamp, nonce, msgSignature); + return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), + wxOpenConfigStorage, timestamp, nonce, msgSignature); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaCategoryListResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaCategoryListResult.java new file mode 100644 index 00000000..af113f16 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaCategoryListResult.java @@ -0,0 +1,31 @@ +package me.chanjar.weixin.open.bean.result; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.open.bean.ma.WxOpenMaCategory; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.io.Serializable; +import java.util.List; + +/** + * 微信开放平台小程序分类目录列表返回 + * + * @author yqx + * @date 2018/9/12 + */ +@Data +public class WxOpenMaCategoryListResult implements Serializable { + + private String errcode; + private String errmsg; + + @SerializedName("category_list") + List categoryList; + + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaDomainResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaDomainResult.java new file mode 100644 index 00000000..79775e4b --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaDomainResult.java @@ -0,0 +1,33 @@ +package me.chanjar.weixin.open.bean.result; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 微信开放平台小程序域名设置返回对象 + * + * @author yqx + * @date 2018/9/12 + */ +@Data +public class WxOpenMaDomainResult implements Serializable { + + private String errcode; + private String errmsg; + + @SerializedName("requestdomain") + List requestdomainList; + + @SerializedName("wsrequestdomain") + List wsrequestdomainList; + + @SerializedName("uploaddomain") + List uploaddomainList; + + @SerializedName("downloaddomain") + List downloaddomainList; + +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaPageListResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaPageListResult.java new file mode 100644 index 00000000..b4c34fb2 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaPageListResult.java @@ -0,0 +1,30 @@ +package me.chanjar.weixin.open.bean.result; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.io.Serializable; +import java.util.List; + +/** + * 微信开放平台小程序第三方提交代码的页面配置列表 + * + * @author yqx + * @date 2018/9/12 + */ +@Data +public class WxOpenMaPageListResult implements Serializable { + + private String errcode; + private String errmsg; + + @SerializedName("page_list") + List pageList; + + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaSubmitAuditResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaSubmitAuditResult.java new file mode 100644 index 00000000..77f150c2 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaSubmitAuditResult.java @@ -0,0 +1,26 @@ +package me.chanjar.weixin.open.bean.result; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 微信开放平台小程序发布代码审核结果 + * + * @author yqx + * @date 2018/9/12 + */ +@Data +public class WxOpenMaSubmitAuditResult implements Serializable { + + private String errcode; + private String errmsg; + + /** + * 审核编号 + */ + @SerializedName("auditid") + Long auditId; + +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaTesterListResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaTesterListResult.java new file mode 100644 index 00000000..91c4af2a --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaTesterListResult.java @@ -0,0 +1,31 @@ +package me.chanjar.weixin.open.bean.result; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.open.bean.ma.WxOpenMaMember; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.io.Serializable; +import java.util.List; + +/** + * 微信开放平台小程序体验者列表返回 + * + * @author yqx + * @date 2018/9/12 + */ +@Data +public class WxOpenMaTesterListResult implements Serializable { + + private String errcode; + private String errmsg; + + @SerializedName("members") + List membersList; + + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeApacheHttpRequestExecutor.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeApacheHttpRequestExecutor.java new file mode 100644 index 00000000..14bed802 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeApacheHttpRequestExecutor.java @@ -0,0 +1,68 @@ +package me.chanjar.weixin.open.util.requestexecuter.ma; + +import me.chanjar.weixin.common.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.open.bean.ma.WxMaQrcodeParam; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.entity.ContentType; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.UUID; + +/** + * @author yqx + * @date 2018-09-13 + */ +public class MaQrCodeApacheHttpRequestExecutor extends MaQrCodeRequestExecutor { + public MaQrCodeApacheHttpRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public File execute(String uri, WxMaQrcodeParam qrcodeParam) throws WxErrorException, IOException { + if (qrcodeParam != null && StringUtils.isNotBlank(qrcodeParam.getPagePath())) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") + ? "path=" + URLEncoder.encode(qrcodeParam.getRequestPath(), "UTF-8") + : "&path=" + URLEncoder.encode(qrcodeParam.getRequestPath(), "UTF-8"); + } + + HttpGet httpGet = new HttpGet(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpGet.setConfig(config); + } + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet); + InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0) { + // 出错 + if (ContentType.TEXT_PLAIN.getMimeType() + .equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp)); + } + } + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } finally { + httpGet.releaseConnection(); + } + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeJoddHttpRequestExecutor.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeJoddHttpRequestExecutor.java new file mode 100644 index 00000000..5c027115 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeJoddHttpRequestExecutor.java @@ -0,0 +1,62 @@ +package me.chanjar.weixin.open.util.requestexecuter.ma; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.util.MimeTypes; +import jodd.util.StringPool; +import me.chanjar.weixin.common.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.open.bean.ma.WxMaQrcodeParam; +import org.apache.commons.lang3.StringUtils; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.UUID; + +/** + * @author yqx + * @date 2018-09-13 + */ +public class MaQrCodeJoddHttpRequestExecutor extends MaQrCodeRequestExecutor { + public MaQrCodeJoddHttpRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public File execute(String uri, WxMaQrcodeParam qrcodeParam) throws WxErrorException, IOException { + if (qrcodeParam != null && StringUtils.isNotBlank(qrcodeParam.getPagePath())) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") + ? "path=" + URLEncoder.encode(qrcodeParam.getRequestPath(), "UTF-8") + : "&path=" + URLEncoder.encode(qrcodeParam.getRequestPath(), "UTF-8"); + } + + + HttpRequest request = HttpRequest.get(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + String contentTypeHeader = response.header("Content-Type"); + if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { + String responseContent = response.bodyText(); + throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp)); + } + try (InputStream inputStream = new ByteArrayInputStream(response.bodyBytes())) { + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeOkhttpRequestExecutor.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeOkhttpRequestExecutor.java new file mode 100644 index 00000000..dbcbac9b --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeOkhttpRequestExecutor.java @@ -0,0 +1,59 @@ +package me.chanjar.weixin.open.util.requestexecuter.ma; + +import me.chanjar.weixin.common.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import me.chanjar.weixin.open.bean.ma.WxMaQrcodeParam; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.UUID; + +/** + * @author yqx + * @date 2018-09-13 + */ +public class MaQrCodeOkhttpRequestExecutor extends MaQrCodeRequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + public MaQrCodeOkhttpRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public File execute(String uri, WxMaQrcodeParam qrcodeParam) throws WxErrorException, IOException { + if (qrcodeParam != null && StringUtils.isNotBlank(qrcodeParam.getPagePath())) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") + ? "path=" + URLEncoder.encode(qrcodeParam.getRequestPath(), "UTF-8") + : "&path=" + URLEncoder.encode(qrcodeParam.getRequestPath(), "UTF-8"); + } + + OkHttpClient client = requestHttp.getRequestHttpClient(); + Request request = new Request.Builder().url(uri).get().build(); + Response response = client.newCall(request).execute(); + String contentTypeHeader = response.header("Content-Type"); + if ("text/plain".equals(contentTypeHeader)) { + String responseContent = response.body().string(); + throw new WxErrorException(WxError.fromJson(responseContent, WxType.MP)); + } + + try (InputStream inputStream = response.body().byteStream()) { + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } + + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeRequestExecutor.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeRequestExecutor.java new file mode 100644 index 00000000..55766d99 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeRequestExecutor.java @@ -0,0 +1,37 @@ +package me.chanjar.weixin.open.util.requestexecuter.ma; + +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.open.bean.ma.WxMaQrcodeParam; + +import java.io.File; + +/** + * 获得小程序体验QrCode图片 请求执行器 + * + * @author yqx + * @date 2018-09-13 + */ +public abstract class MaQrCodeRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; + + public MaQrCodeRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } + + public static RequestExecutor create(RequestHttp requestHttp) throws WxErrorException { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new MaQrCodeApacheHttpRequestExecutor(requestHttp); + case JODD_HTTP: + return new MaQrCodeJoddHttpRequestExecutor(requestHttp); + case OK_HTTP: + return new MaQrCodeOkhttpRequestExecutor(requestHttp); + default: + throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("不支持的http框架").build()); + } + } + +} diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index 34105697..b348a9b9 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ weixin-java-parent com.github.binarywang - 3.1.0 + 3.2.0 4.0.0 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayApiData.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayApiData.java index db9a8833..f8277d15 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayApiData.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayApiData.java @@ -35,6 +35,8 @@ public class WxPayApiData { private String exceptionMsg; /** + * Instantiates a new Wx pay api data. + * * @param url 接口请求地址 * @param requestData 请求数据 * @param responseData 响应数据 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponSendRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponSendRequest.java index d6d9f73d..5fa6da7d 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponSendRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponSendRequest.java @@ -13,7 +13,6 @@ import me.chanjar.weixin.common.annotation.Required; * * @author Binary Wang */ - @Data @EqualsAndHashCode(callSuper = true) @Builder(builderMethodName = "newBuilder") diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryRequest.java index c7f7cadf..b8a78b40 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryRequest.java @@ -13,7 +13,6 @@ import me.chanjar.weixin.common.annotation.Required; * * @author Binary Wang */ - @Data @EqualsAndHashCode(callSuper = true) @Builder(builderMethodName = "newBuilder") diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankQueryRequest.java index 804d305b..83d74192 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankQueryRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankQueryRequest.java @@ -1,10 +1,9 @@ package com.github.binarywang.wxpay.bean.entpay; -import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest; import com.thoughtworks.xstream.annotations.XStreamAlias; -import lombok.*; -import me.chanjar.weixin.common.annotation.Required; -import me.chanjar.weixin.common.util.ToStringUtils; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; /** *
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankRequest.java
index a96a547d..05ccebc2 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayBankRequest.java
@@ -117,8 +117,8 @@ public class EntPayBankRequest extends BaseWxPayRequest {
   }
 
   @Override
-  protected boolean ignoreSignType() {
-    return true;
+  protected String[] getIgnoredParamsForSign() {
+    return new String[]{"sign_type"};
   }
 
   @Override
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayQueryRequest.java
index 3f1a240a..987677a3 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayQueryRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayQueryRequest.java
@@ -1,10 +1,16 @@
 package com.github.binarywang.wxpay.bean.entpay;
 
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
-import lombok.*;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
 import me.chanjar.weixin.common.annotation.Required;
-import me.chanjar.weixin.common.util.ToStringUtils;
 
 /**
  * 
@@ -44,11 +50,11 @@ public class EntPayQueryRequest extends BaseWxPayRequest {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   @Override
-  protected boolean ignoreSignType() {
-    return true;
+  protected String[] getIgnoredParamsForSign() {
+    return new String[]{"sign_type"};
   }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayRequest.java
index 1ff25e78..285b66ba 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayRequest.java
@@ -1,10 +1,16 @@
 package com.github.binarywang.wxpay.bean.entpay;
 
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
-import lombok.*;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
 import me.chanjar.weixin.common.annotation.Required;
-import me.chanjar.weixin.common.util.ToStringUtils;
 
 /**
  * 
@@ -14,7 +20,6 @@ import me.chanjar.weixin.common.util.ToStringUtils;
  *
  * @author Binary Wang
  */
-
 @Data
 @EqualsAndHashCode(callSuper = true)
 @Builder(builderMethodName = "newBuilder")
@@ -188,11 +193,11 @@ public class EntPayRequest extends BaseWxPayRequest {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   @Override
-  protected boolean ignoreSignType() {
-    return true;
+  protected String[] getIgnoredParamsForSign() {
+    return new String[]{"sign_type"};
   }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayResult.java
index 17b30312..223c1963 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayResult.java
@@ -19,34 +19,39 @@ import lombok.NoArgsConstructor;
 @NoArgsConstructor
 @XStreamAlias("xml")
 public class EntPayResult extends BaseWxPayResult {
+  /**
+   * 商户号.
+   */
+  @XStreamAlias("mchid")
+  private String mchId;
 
   /**
-   * 商户appid
+   * 商户appid.
    */
   @XStreamAlias("mch_appid")
   private String mchAppid;
 
   /**
-   * 设备号
+   * 设备号.
    */
   @XStreamAlias("device_info")
   private String deviceInfo;
 
   //############以下字段在return_code 和result_code都为SUCCESS的时候有返回##############
   /**
-   * 商户订单号
+   * 商户订单号.
    */
   @XStreamAlias("partner_trade_no")
   private String partnerTradeNo;
 
   /**
-   * 微信订单号
+   * 微信订单号.
    */
   @XStreamAlias("payment_no")
   private String paymentNo;
 
   /**
-   * 微信支付成功时间
+   * 微信支付成功时间.
    */
   @XStreamAlias("payment_time")
   private String paymentTime;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponse.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponse.java
index c7adf850..c71ed7de 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponse.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponse.java
@@ -32,6 +32,12 @@ public class WxPayNotifyResponse {
   @XStreamAlias("return_msg")
   private String returnMsg;
 
+  /**
+   * Fail string.
+   *
+   * @param msg the msg
+   * @return the string
+   */
   public static String fail(String msg) {
     WxPayNotifyResponse response = new WxPayNotifyResponse(FAIL, msg);
     XStream xstream = XStreamInitializer.getInstance();
@@ -39,6 +45,12 @@ public class WxPayNotifyResponse {
     return xstream.toXML(response);
   }
 
+  /**
+   * Success string.
+   *
+   * @param msg the msg
+   * @return the string
+   */
   public static String success(String msg) {
     WxPayNotifyResponse response = new WxPayNotifyResponse(SUCCESS, msg);
     XStream xstream = XStreamInitializer.getInstance();
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyCoupon.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyCoupon.java
index 80da09e6..cb1d6c24 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyCoupon.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyCoupon.java
@@ -1,15 +1,19 @@
 package com.github.binarywang.wxpay.bean.notify;
 
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import me.chanjar.weixin.common.util.ToStringUtils;
-
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
 /**
- * 支付异步通知代金券详细
+ * 支付异步通知代金券详细.
+ *
+ * @author aimilin
  */
 @Data
 @NoArgsConstructor
@@ -20,6 +24,12 @@ public class WxPayOrderNotifyCoupon implements Serializable {
   private String couponType;
   private Integer couponFee;
 
+  /**
+   * To map map.
+   *
+   * @param index the index
+   * @return the map
+   */
   public Map toMap(int index) {
     Map map = new HashMap<>();
     map.put("coupon_id_" + index, this.getCouponId());
@@ -30,6 +40,6 @@ public class WxPayOrderNotifyCoupon implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java
index 006fe1d7..9fc9cebe 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java
@@ -1,5 +1,11 @@
 package com.github.binarywang.wxpay.bean.notify;
 
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
 import com.github.binarywang.wxpay.converter.WxPayOrderNotifyResultConverter;
 import com.github.binarywang.wxpay.util.SignUtils;
@@ -8,12 +14,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
 
-import java.util.List;
-import java.util.Map;
-
 /**
  * 支付结果通用通知 ,文档见:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
  *
@@ -283,6 +285,12 @@ public class WxPayOrderNotifyResult extends BaseWxPayResult {
   @XStreamAlias("version")
   private String version;
 
+  /**
+   * From xml wx pay order notify result.
+   *
+   * @param xmlString the xml string
+   * @return the wx pay order notify result
+   */
   public static WxPayOrderNotifyResult fromXML(String xmlString) {
     XStream xstream = XStreamInitializer.getInstance();
     xstream.processAnnotations(WxPayOrderNotifyResult.class);
@@ -306,6 +314,6 @@ public class WxPayOrderNotifyResult extends BaseWxPayResult {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java
index 94e8492b..f738984a 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java
@@ -1,5 +1,14 @@
 package com.github.binarywang.wxpay.bean.notify;
 
+import java.io.Serializable;
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.thoughtworks.xstream.XStream;
@@ -8,15 +17,7 @@ import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
-import org.apache.commons.codec.binary.Base64;
-
-import javax.crypto.Cipher;
-import javax.crypto.spec.SecretKeySpec;
-import java.io.Serializable;
-import java.math.BigInteger;
-import java.security.MessageDigest;
 
 /**
  * 
@@ -39,17 +40,17 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
    *
    * @param xmlString xml字符串
    * @param mchKey    商户密钥
+   * @return the wx pay refund notify result
+   * @throws WxPayException the wx pay exception
    */
   public static WxPayRefundNotifyResult fromXML(String xmlString, String mchKey) throws WxPayException {
     WxPayRefundNotifyResult result = BaseWxPayResult.fromXML(xmlString, WxPayRefundNotifyResult.class);
     String reqInfoString = result.getReqInfoString();
     try {
-      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
-
-      final MessageDigest md5 = MessageDigest.getInstance("MD5");
-      md5.update(mchKey.getBytes());
-      final String keyMd5String = new BigInteger(1, md5.digest()).toString(16).toLowerCase();
+      final String keyMd5String = DigestUtils.md5Hex(mchKey).toLowerCase();
       SecretKeySpec key = new SecretKeySpec(keyMd5String.getBytes(), "AES");
+
+      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
       cipher.init(Cipher.DECRYPT_MODE, key);
       result.setReqInfo(ReqInfo.fromXML(new String(cipher.doFinal(Base64.decodeBase64(reqInfoString)))));
     } catch (Exception e) {
@@ -74,7 +75,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
   private ReqInfo reqInfo;
 
   /**
-   * 加密信息字段解密后的内容
+   * 加密信息字段解密后的内容.
    */
   @Data
   @NoArgsConstructor
@@ -82,12 +83,12 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
   public static class ReqInfo {
     @Override
     public String toString() {
-      return ToStringUtils.toSimpleString(this);
+      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
     }
 
     /**
      * 
-     * 字段名:微信订单号
+     * 字段名:微信订单号.
      * 变量名:transaction_id
      * 是否必填:是
      * 类型:String(32)
@@ -100,7 +101,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
 
     /**
      * 
-     * 字段名:商户订单号
+     * 字段名:商户订单号.
      * 变量名:out_trade_no
      * 是否必填:是
      * 类型:String(32)
@@ -113,7 +114,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
 
     /**
      * 
-     * 字段名:微信退款单号
+     * 字段名:微信退款单号.
      * 变量名:refund_id
      * 是否必填:是
      * 类型:String(28)
@@ -126,7 +127,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
 
     /**
      * 
-     * 字段名:商户退款单号
+     * 字段名:商户退款单号.
      * 变量名:out_refund_no
      * 是否必填:是
      * 类型:String(64)
@@ -139,7 +140,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
 
     /**
      * 
-     * 字段名:订单金额
+     * 字段名:订单金额.
      * 变量名:total_fee
      * 是否必填:是
      * 类型:Int
@@ -152,7 +153,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
 
     /**
      * 
-     * 字段名:结订单金额
+     * 字段名:结订单金额.
      * 变量名:settlement_total_fee
      * 是否必填:否
      * 类型:Int
@@ -165,7 +166,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
 
     /**
      * 
-     * 字段名:申请退款金额
+     * 字段名:申请退款金额.
      * 变量名:refund_fee
      * 是否必填:是
      * 类型:Int
@@ -178,7 +179,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
 
     /**
      * 
-     * 字段名:退款金额
+     * 字段名:退款金额.
      * 变量名:settlement_refund_fee
      * 是否必填:是
      * 类型:Int
@@ -191,7 +192,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
 
     /**
      * 
-     * 字段名:退款状态
+     * 字段名:退款状态.
      * 变量名:refund_status
      * 是否必填:是
      * 类型:String(16)
@@ -204,7 +205,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
 
     /**
      * 
-     * 字段名:退款成功时间
+     * 字段名:退款成功时间.
      * 变量名:success_time
      * 是否必填:否
      * 类型: String(20)
@@ -216,7 +217,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
 
     /**
      * 
-     * 字段名:退款入账账户
+     * 字段名:退款入账账户.
      * 变量名:refund_recv_accout
      * 是否必填:是
      * 类型:String(64)
@@ -229,7 +230,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
 
     /**
      * 
-     * 字段名:退款资金来源
+     * 字段名:退款资金来源.
      * 变量名:refund_account
      * 是否必填:是
      * 类型:String(30)
@@ -242,7 +243,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
 
     /**
      * 
-     * 字段名:退款发起来源
+     * 字段名:退款发起来源.
      * 变量名:refund_request_source
      * 是否必填:是
      * 类型:String(30)
@@ -253,6 +254,12 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
     @XStreamAlias("refund_request_source")
     private String refundRequestSource;
 
+    /**
+     * From xml req info.
+     *
+     * @param xmlString the xml string
+     * @return the req info
+     */
     public static ReqInfo fromXML(String xmlString) {
       XStream xstream = XStreamInitializer.getInstance();
       xstream.processAnnotations(ReqInfo.class);
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java
index d940b7a4..3824e159 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java
@@ -1,5 +1,12 @@
 package com.github.binarywang.wxpay.bean.request;
 
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import com.github.binarywang.wxpay.config.WxPayConfig;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.util.SignUtils;
@@ -8,12 +15,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.Data;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.BeanUtils;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
 
 import static com.github.binarywang.wxpay.constant.WxPayConstants.SignType.ALL_SIGN_TYPES;
 
@@ -31,7 +33,7 @@ public abstract class BaseWxPayRequest implements Serializable {
 
   /**
    * 
-   * 字段名:公众账号ID
+   * 字段名:公众账号ID.
    * 变量名:appid
    * 是否必填:是
    * 类型:String(32)
@@ -43,7 +45,7 @@ public abstract class BaseWxPayRequest implements Serializable {
   protected String appid;
   /**
    * 
-   * 字段名:商户号
+   * 字段名:商户号.
    * 变量名:mch_id
    * 是否必填:是
    * 类型:String(32)
@@ -55,7 +57,7 @@ public abstract class BaseWxPayRequest implements Serializable {
   protected String mchId;
   /**
    * 
-   * 字段名:服务商模式下的子商户公众账号ID
+   * 字段名:服务商模式下的子商户公众账号ID.
    * 变量名:sub_appid
    * 是否必填:是
    * 类型:String(32)
@@ -67,7 +69,7 @@ public abstract class BaseWxPayRequest implements Serializable {
   protected String subAppId;
   /**
    * 
-   * 字段名:服务商模式下的子商户号
+   * 字段名:服务商模式下的子商户号.
    * 变量名:sub_mch_id
    * 是否必填:是
    * 类型:String(32)
@@ -79,7 +81,7 @@ public abstract class BaseWxPayRequest implements Serializable {
   protected String subMchId;
   /**
    * 
-   * 字段名:随机字符串
+   * 字段名:随机字符串.
    * 变量名:nonce_str
    * 是否必填:是
    * 类型:String(32)
@@ -91,7 +93,7 @@ public abstract class BaseWxPayRequest implements Serializable {
   protected String nonceStr;
   /**
    * 
-   * 字段名:签名
+   * 字段名:签名.
    * 变量名:sign
    * 是否必填:是
    * 类型:String(32)
@@ -104,7 +106,7 @@ public abstract class BaseWxPayRequest implements Serializable {
 
   /**
    * 
-   * 签名类型
+   * 签名类型.
    * sign_type
    * 否
    * String(32)
@@ -116,16 +118,17 @@ public abstract class BaseWxPayRequest implements Serializable {
   private String signType;
 
   /**
-   * 将单位为元转换为单位为分
+   * 将单位为元转换为单位为分.
    *
    * @param yuan 将要转换的元的数值字符串
+   * @return the integer
    */
   public static Integer yuanToFen(String yuan) {
     return new BigDecimal(yuan).setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).intValue();
   }
 
   /**
-   * 检查请求参数内容,包括必填参数以及特殊约束
+   * 检查请求参数内容,包括必填参数以及特殊约束.
    */
   private void checkFields() throws WxPayException {
     //check required fields
@@ -140,12 +143,14 @@ public abstract class BaseWxPayRequest implements Serializable {
   }
 
   /**
-   * 检查约束情况
+   * 检查约束情况.
+   *
+   * @throws WxPayException the wx pay exception
    */
   protected abstract void checkConstraints() throws WxPayException;
 
   /**
-   * 如果配置中已经设置,可以不设置值
+   * 如果配置中已经设置,可以不设置值.
    *
    * @param appid 微信公众号appid
    */
@@ -154,7 +159,7 @@ public abstract class BaseWxPayRequest implements Serializable {
   }
 
   /**
-   * 如果配置中已经设置,可以不设置值
+   * 如果配置中已经设置,可以不设置值.
    *
    * @param mchId 微信商户号
    */
@@ -163,7 +168,7 @@ public abstract class BaseWxPayRequest implements Serializable {
   }
 
   /**
-   * 默认采用时间戳为随机字符串,可以不设置
+   * 默认采用时间戳为随机字符串,可以不设置.
    *
    * @param nonceStr 随机字符串
    */
@@ -173,9 +178,14 @@ public abstract class BaseWxPayRequest implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
+  /**
+   * To xml string.
+   *
+   * @return the string
+   */
   public String toXML() {
     XStream xstream = XStreamInitializer.getInstance();
     //涉及到服务商模式的两个参数,在为空值时置为null,以免在请求时将空值传给微信服务器
@@ -186,28 +196,33 @@ public abstract class BaseWxPayRequest implements Serializable {
   }
 
   /**
-   * 签名时,是否忽略signType
+   * 签名时,是否忽略appid.
+   *
+   * @return the boolean
    */
-  protected boolean ignoreSignType() {
+  protected boolean ignoreAppid() {
     return false;
   }
 
   /**
-   * 签名时,是否忽略appid
+   * 签名时,忽略的参数.
+   *
+   * @return the string [ ]
    */
-  protected boolean ignoreAppid() {
-    return false;
+  protected String[] getIgnoredParamsForSign() {
+    return new String[0];
   }
 
   /**
    * 
-   * 检查参数,并设置签名
+   * 检查参数,并设置签名.
    * 1、检查参数(注意:子类实现需要检查参数的而外功能时,请在调用父类的方法前进行相应判断)
    * 2、补充系统参数,如果未传入则从配置里读取
    * 3、生成签名,并设置进去
    * 
* * @param config 支付配置对象,用于读取相应系统配置信息 + * @throws WxPayException the wx pay exception */ public void checkAndSign(WxPayConfig config) throws WxPayException { this.checkFields(); @@ -246,7 +261,6 @@ public abstract class BaseWxPayRequest implements Serializable { } //设置签名字段的值 - this.setSign(SignUtils.createSign(this, this.getSignType(), config.getMchKey(), - this.ignoreSignType())); + this.setSign(SignUtils.createSign(this, this.getSignType(), config.getMchKey(), this.getIgnoredParamsForSign())); } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDefaultRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDefaultRequest.java index d37ed7ff..e44a6111 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDefaultRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDefaultRequest.java @@ -16,4 +16,9 @@ public class WxPayDefaultRequest extends BaseWxPayRequest { protected void checkConstraints() { //do nothing } + + @Override + protected boolean ignoreAppid() { + return true; + } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadFundFlowRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadFundFlowRequest.java new file mode 100644 index 00000000..8ce06238 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadFundFlowRequest.java @@ -0,0 +1,90 @@ +package com.github.binarywang.wxpay.bean.request; + +import com.github.binarywang.wxpay.constant.WxPayConstants.AccountType; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import lombok.*; +import me.chanjar.weixin.common.annotation.Required; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; + +/** + *
+ *   微信支付下载资金账单请求参数类
+ * Created by cwivan on 2018-08-02.
+ * 
+ * + * @author cwivan + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Builder(builderMethodName = "newBuilder") +@NoArgsConstructor +@AllArgsConstructor +@XStreamAlias("xml") +public class WxPayDownloadFundFlowRequest extends BaseWxPayRequest { + private static final String[] ACCOUNT_TYPES = new String[]{AccountType.BASIC, AccountType.OPERATION, AccountType.FEES}; + private static final String SIGN_TYPE_HMAC_SHA256 = "HMAC-SHA256"; + private static final String TAR_TYPE_GZIP = "GZIP"; + + /** + *
+   * 对账单日期
+   * bill_date
+   * 是
+   * String(8)
+   * 20140603
+   * 下载对账单的日期,格式:20140603
+   * 
+ */ + @Required + @XStreamAlias("bill_date") + private String billDate; + + /** + *
+   * 资金账户类型
+   * account_type
+   * 是
+   * Basic
+   * String(8)
+   * --Basic,基本账户
+   * --Operation,运营账户
+   * --Fees,手续费账户
+   * 
+ */ + @Required + @XStreamAlias("account_type") + private String accountType; + + /** + *
+   * 压缩账单
+   * tar_type
+   * 否
+   * String(8)
+   * GZIP
+   * 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。
+   * 
+ */ + @XStreamAlias("tar_type") + private String tarType; + + @Override + protected void checkConstraints() throws WxPayException { + if (StringUtils.isNotBlank(this.getTarType()) && !TAR_TYPE_GZIP.equals(this.getTarType())) { + throw new WxPayException("tar_type值如果存在,只能为GZIP"); + } + + if (!ArrayUtils.contains(ACCOUNT_TYPES, this.getAccountType())) { + throw new WxPayException(String.format("account_type必须为%s其中之一,实际值:%s", + Arrays.toString(ACCOUNT_TYPES), this.getAccountType())); + } + /** + * 目前仅支持HMAC-SHA256 + */ + this.setSignType(SIGN_TYPE_HMAC_SHA256); + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayQueryCommentRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayQueryCommentRequest.java index d052a26e..6b81aeed 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayQueryCommentRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayQueryCommentRequest.java @@ -7,7 +7,7 @@ import me.chanjar.weixin.common.annotation.Required; /** *
- *  拉取订单评价数据接口的请求参数封装类
+ *  拉取订单评价数据接口的请求参数封装类.
  *  Created by BinaryWang on 2017/9/2.
  * 
* @@ -20,14 +20,11 @@ import me.chanjar.weixin.common.annotation.Required; @AllArgsConstructor @XStreamAlias("xml") public class WxPayQueryCommentRequest extends BaseWxPayRequest { - @Override - protected boolean ignoreSignType() { - return true; - } + private static final long serialVersionUID = 2633600418272768186L; /** *
-   * 字段名:开始时间
+   * 字段名:开始时间.
    * 变量名:begin_time
    * 是否必填:是
    * 类型:String(19)
@@ -41,7 +38,7 @@ public class WxPayQueryCommentRequest extends BaseWxPayRequest {
 
   /**
    * 
-   * 字段名:结束时间
+   * 字段名:结束时间.
    * 变量名:end_time
    * 是否必填:是
    * 类型:String(19)
@@ -55,7 +52,7 @@ public class WxPayQueryCommentRequest extends BaseWxPayRequest {
 
   /**
    * 
-   * 字段名:位移
+   * 字段名:位移.
    * 变量名:offset
    * 是否必填:是
    * 类型:uint(64)
@@ -69,7 +66,7 @@ public class WxPayQueryCommentRequest extends BaseWxPayRequest {
 
   /**
    * 
-   * 字段名:条数
+   * 字段名:条数.
    * 变量名:limit
    * 是否必填:否
    * 类型:uint(32)
@@ -81,11 +78,14 @@ public class WxPayQueryCommentRequest extends BaseWxPayRequest {
   private Integer limit;
 
   /**
-   * 检查约束情况
+   * 检查约束情况.
    */
   @Override
   protected void checkConstraints() throws WxPayException {
-
   }
 
+  @Override
+  protected String[] getIgnoredParamsForSign() {
+    return new String[]{"limit","sign_type"};
+  }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPaySendRedpackRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPaySendRedpackRequest.java
index f97ade0c..4b868a95 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPaySendRedpackRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPaySendRedpackRequest.java
@@ -1,10 +1,14 @@
 package com.github.binarywang.wxpay.bean.request;
 
 import com.thoughtworks.xstream.annotations.XStreamAlias;
-import lombok.*;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
 
 /**
- * 发送红包请求参数对象
+ * 发送红包请求参数对象.
  * Created by Binary Wang on 2016/9/24.
  *
  * @author Binary Wang
@@ -16,15 +20,21 @@ import lombok.*;
 @AllArgsConstructor
 @XStreamAlias("xml")
 public class WxPaySendRedpackRequest extends BaseWxPayRequest {
+  @Override
+  protected String[] getIgnoredParamsForSign() {
+    return new String[]{"sign_type"};
+  }
+
   /**
-   * mch_billno
-   * 商户订单号(每个订单号必须唯一)  组成:mch_id+yyyymmdd+10位一天内不能重复的数字。  接口根据商户订单号支持重入,如出现超时可再调用。
+   * mch_billno.
+   * 商户订单号(每个订单号必须唯一)
+   * 组成:mch_id+yyyymmdd+10位一天内不能重复的数字。  接口根据商户订单号支持重入,如出现超时可再调用。
    */
   @XStreamAlias("mch_billno")
   private String mchBillNo;
 
   /**
-   * send_name
+   * send_name.
    * 商户名称
    * 红包发送者名称
    */
@@ -32,14 +42,14 @@ public class WxPaySendRedpackRequest extends BaseWxPayRequest {
   private String sendName;
 
   /**
-   * re_openid
+   * re_openid.
    * 接受红包的用户   用户在wxappid下的openid
    */
   @XStreamAlias("re_openid")
   private String reOpenid;
 
   /**
-   * total_amount
+   * total_amount.
    * 红包总额
    */
   @XStreamAlias("total_amount")
@@ -53,7 +63,7 @@ public class WxPaySendRedpackRequest extends BaseWxPayRequest {
   private Integer totalNum;
 
   /**
-   * amt_type
+   * amt_type.
    * 红包金额设置方式
    * ALL_RAND—全部随机,商户指定总金额和红包发放总人数,由微信支付随机计算出各红包金额
    * 裂变红包必填
@@ -62,14 +72,14 @@ public class WxPaySendRedpackRequest extends BaseWxPayRequest {
   private String amtType;
 
   /**
-   * wishing
+   * wishing.
    * 红包祝福语
    */
   @XStreamAlias("wishing")
   private String wishing;
 
   /**
-   * client_ip
+   * client_ip.
    * 服务器Ip地址
    * 调用接口的机器Ip地址
    */
@@ -77,21 +87,21 @@ public class WxPaySendRedpackRequest extends BaseWxPayRequest {
   private String clientIp;
 
   /**
-   * act_name
+   * act_name.
    * 活动名称
    */
   @XStreamAlias("act_name")
   private String actName;
 
   /**
-   * remark
+   * remark.
    * 备注
    */
   @XStreamAlias("remark")
   private String remark;
 
   /**
-   * wxappid
+   * wxappid.
    * 微信分配的公众账号ID(企业号corpid即为此appId)。接口传入的所有appid应该为公众号的appid(在mp.weixin.qq.com申请的),不能为APP的appid(在open.weixin.qq.com申请的)
    */
   @XStreamAlias("wxappid")
@@ -99,7 +109,7 @@ public class WxPaySendRedpackRequest extends BaseWxPayRequest {
 
   /**
    * 
-   * scene_id
+   * scene_id.
    * 场景id
    * PRODUCT_1:商品促销
    * PRODUCT_2:抽奖
@@ -117,7 +127,7 @@ public class WxPaySendRedpackRequest extends BaseWxPayRequest {
 
   /**
    * 
-   * risk_info
+   * risk_info.
    * 活动信息
    * posttime:用户操作的时间戳
    * mobile:业务系统账号的手机号,国家代码-手机号。不需要+号
@@ -133,7 +143,7 @@ public class WxPaySendRedpackRequest extends BaseWxPayRequest {
 
   /**
    * 
-   * consume_mch_id
+   * consume_mch_id.
    * 资金授权商户号
    * 资金授权商户号
    * 服务商替特约商户发放时使用
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java
index 1cdfe51a..ad014fc2 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java
@@ -1,5 +1,26 @@
 package com.github.binarywang.wxpay.bean.result;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.util.SignUtils;
@@ -9,26 +30,7 @@ import com.google.common.collect.Maps;
 import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.Data;
-import me.chanjar.weixin.common.util.ToStringUtils;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpressionException;
-import javax.xml.xpath.XPathFactory;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.Map;
 
 /**
  * 
@@ -114,13 +116,19 @@ public abstract class BaseWxPayResult implements Serializable {
    * 将单位分转换成单位圆.
    *
    * @param fen 将要被转换为元的分的数值
+   * @return the string
    */
   public static String fenToYuan(Integer fen) {
-    return new BigDecimal(Double.valueOf(fen) / 100).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString();
+    return BigDecimal.valueOf(Double.valueOf(fen) / 100).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString();
   }
 
   /**
    * 从xml字符串创建bean对象.
+   *
+   * @param        the type parameter
+   * @param xmlString the xml string
+   * @param clz       the clz
+   * @return the t
    */
   public static  T fromXML(String xmlString, Class clz) {
     XStream xstream = XStreamInitializer.getInstance();
@@ -130,17 +138,24 @@ public abstract class BaseWxPayResult implements Serializable {
     return result;
   }
 
+  /**
+   * Gets logger.
+   *
+   * @return the logger
+   */
   protected Logger getLogger() {
     return LoggerFactory.getLogger(this.getClass());
   }
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   /**
    * 将bean通过保存的xml字符串转换成map.
+   *
+   * @return the map
    */
   public Map toMap() {
     if (StringUtils.isBlank(this.xmlString)) {
@@ -187,6 +202,9 @@ public abstract class BaseWxPayResult implements Serializable {
 
   /**
    * 获取xml中元素的值.
+   *
+   * @param path the path
+   * @return the xml value
    */
   String getXmlValue(String... path) {
     Document doc = this.getXmlDoc();
@@ -204,6 +222,9 @@ public abstract class BaseWxPayResult implements Serializable {
 
   /**
    * 获取xml中元素的值,作为int值返回.
+   *
+   * @param path the path
+   * @return the xml value as int
    */
   Integer getXmlValueAsInt(String... path) {
     String result = this.getXmlValue(path);
@@ -217,8 +238,10 @@ public abstract class BaseWxPayResult implements Serializable {
   /**
    * 校验返回结果签名.
    *
+   * @param wxPayService the wx pay service
    * @param signType     签名类型
    * @param checkSuccess 是否同时检查结果是否成功
+   * @throws WxPayException the wx pay exception
    */
   public void checkResult(WxPayService wxPayService, String signType, boolean checkSuccess) throws WxPayException {
     //校验返回结果签名
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult.java
index 28ed6e7f..a9b3e46c 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult.java
@@ -1,15 +1,19 @@
 package com.github.binarywang.wxpay.bean.result;
 
+import java.io.Serializable;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import lombok.Data;
 import lombok.NoArgsConstructor;
-import me.chanjar.weixin.common.util.ToStringUtils;
-
-import java.io.Serializable;
 
 /**
  * 交易时间:2017-04-06 01:00:02 公众账号ID: 商户号: 子商户号:0 设备号:WEB 微信订单号: 商户订单号:2017040519091071873216 用户标识: 交易类型:NATIVE
  * 交易状态:REFUND 付款银行:CFT 货币种类:CNY 总金额:0.00 企业红包金额:0.00 微信退款单号: 商户退款单号:20170406010000933 退款金额:0.01 企业红包退款金额:0.00
  * 退款类型:ORIGINAL 退款状态:SUCCESS 商品名称: 商户数据包: 手续费:0.00000 费率 :0.60%
+ *
+ * @author BinaryWang
  */
 @Data
 @NoArgsConstructor
@@ -18,103 +22,103 @@ public class WxPayBillBaseResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   /**
-   * 交易时间
+   * 交易时间.
    */
   private String tradeTime;
   /**
-   * 公众账号ID
+   * 公众账号ID.
    */
   private String appId;
   /**
-   * 商户号
+   * 商户号.
    */
   private String mchId;
   /**
-   * 子商户号
+   * 子商户号.
    */
   private String subMchId;
   /**
-   * 设备号
+   * 设备号.
    */
   private String deviceInfo;
   /**
-   * 微信订单号
+   * 微信订单号.
    */
   private String transactionId;
   /**
-   * 商户订单号
+   * 商户订单号.
    */
   private String outTradeNo;
   /**
-   * 用户标识
+   * 用户标识.
    */
   private String openId;
   /**
-   * 交易类型
+   * 交易类型.
    */
   private String tradeType;
   /**
-   * 交易状态
+   * 交易状态.
    */
   private String tradeState;
   /**
-   * 付款银行
+   * 付款银行.
    */
   private String bankType;
   /**
-   * 货币种类
+   * 货币种类.
    */
   private String feeType;
   /**
-   * 总金额
+   * 总金额.
    */
   private String totalFee;
   /**
-   * 企业红包金额
+   * 企业红包金额.
    */
   private String couponFee;
   /**
-   * 微信退款单号
+   * 微信退款单号.
    */
   private String refundId;
   /**
-   * 商户退款单号
+   * 商户退款单号.
    */
   private String outRefundNo;
   /**
-   * 退款金额
+   * 退款金额.
    */
   private String settlementRefundFee;
   /**
-   * 企业红包退款金额
+   * 企业红包退款金额.
    */
   private String couponRefundFee;
   /**
-   * 退款类型
+   * 退款类型.
    */
   private String refundChannel;
   /**
-   * 退款状态
+   * 退款状态.
    */
   private String refundState;
   /**
-   * 商品名称
+   * 商品名称.
    */
   private String body;
   /**
-   * 商户数据包
+   * 商户数据包.
    */
   private String attach;
   /**
-   * 手续费
+   * 手续费.
    */
   private String poundage;
   /**
-   * 费率
+   * 费率.
    */
   private String poundageRate;
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult.java
index 0a1a4b25..a8f9f7c5 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult.java
@@ -1,12 +1,19 @@
 package com.github.binarywang.wxpay.bean.result;
 
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import me.chanjar.weixin.common.util.ToStringUtils;
-
 import java.io.Serializable;
 import java.util.List;
 
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * The type Wx pay bill result.
+ *
+ * @author BinaryWang
+ */
 @Data
 @NoArgsConstructor
 public class WxPayBillResult implements Serializable {
@@ -14,31 +21,31 @@ public class WxPayBillResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
   }
 
   /**
-   * 对账返回对象
+   * 对账返回对象.
    */
   private List wxPayBillBaseResultLst;
   /**
-   * 总交易单数
+   * 总交易单数.
    */
   private String totalRecord;
   /**
-   * 总交易额
+   * 总交易额.
    */
   private String totalFee;
   /**
-   * 总退款金额
+   * 总退款金额.
    */
   private String totalRefundFee;
   /**
-   * 总代金券或立减优惠退款金额
+   * 总代金券或立减优惠退款金额.
    */
   private String totalCouponFee;
   /**
-   * 手续费总金额
+   * 手续费总金额.
    */
   private String totalPoundageFee;
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayCommonResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayCommonResult.java
index 242a30a1..cc0a3a6e 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayCommonResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayCommonResult.java
@@ -10,7 +10,6 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
  *
  * @author Binary Wang
  */
-
 @XStreamAlias("xml")
 public class WxPayCommonResult extends BaseWxPayResult {
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowBaseResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowBaseResult.java
new file mode 100644
index 00000000..dc631314
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowBaseResult.java
@@ -0,0 +1,71 @@
+package com.github.binarywang.wxpay.bean.result;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+
+/**
+ * 记账时间:2018-02-01 04:21:23 微信支付业务单号:50000305742018020103387128253 资金流水单号:1900009231201802015884652186 业务名称:退款
+ * 业务类型:退款 收支类型:支出 收支金额(元):0.02 账户结余(元):0.17 资金变更提交申请人:system 备注:缺货 业务凭证号:REF4200000068201801293084726067
+ *
+ * @author cwivan
+ */
+@Data
+@NoArgsConstructor
+public class WxPayFundFlowBaseResult implements Serializable {
+  private static final long serialVersionUID = 4474557532904682718L;
+
+  @Override
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
+
+  /**
+   * 记账时间
+   */
+  private String BillingTime;
+  /**
+   * 微信支付业务单号
+   */
+  private String bizTransactionId;
+  /**
+   * 资金流水单号
+   */
+  private String fundFlowId;
+  /**
+   * 业务名称
+   */
+  private String bizName;
+  /**
+   * 业务类型
+   */
+  private String bizType;
+  /**
+   * 收支类型
+   */
+  private String financialType;
+  /**
+   * 收支金额(元)
+   */
+  private String financialFee;
+  /**
+   * 账户结余(元)
+   */
+  private String AccountBalance;
+  /**
+   * 资金变更提交申请人
+   */
+  private String fundApplicant;
+  /**
+   * 备注
+   */
+  private String memo;
+  /**
+   * 业务凭证号
+   */
+  private String bizVoucherId;
+
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowResult.java
new file mode 100644
index 00000000..ba325504
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowResult.java
@@ -0,0 +1,60 @@
+package com.github.binarywang.wxpay.bean.result;
+
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 
+ * 下载资金账单接口响应结果对象类
+ * Created by cwivan on 2018-08-02.
+ * 
+ * + * @author cwivan + */ +@Data +@NoArgsConstructor +public class WxPayFundFlowResult implements Serializable{ + private static final long serialVersionUID = 8371500036495349207L; + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + + /** + * 资金流水返回对象 + */ + private List wxPayFundFlowBaseResultList; + + /** + * 资金流水总笔数 + */ + private String totalRecord; + + /** + * 收入笔数 + */ + private String incomeRecord; + + /** + * 收入金额 + */ + private String incomeAmount; + + /** + * 支出笔数 + */ + private String expenditureRecord; + + /** + * 支出金额 + */ + private String expenditureAmount; + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryResult.java index dd37fa7a..c54c5368 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryResult.java @@ -267,6 +267,9 @@ public class WxPayOrderQueryResult extends BaseWxPayResult { } } + /** + * The type Coupon. + */ @Data @Builder(builderMethodName = "newBuilder") @AllArgsConstructor diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRedpackQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRedpackQueryResult.java index 3fdfe333..4f05bfde 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRedpackQueryResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRedpackQueryResult.java @@ -223,6 +223,9 @@ public class WxPayRedpackQueryResult extends BaseWxPayResult { @XStreamAlias("hblist") private List redpackList; + /** + * The type Redpack info. + */ @Data @XStreamAlias("hbinfo") public static class RedpackInfo implements Serializable { diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundQueryResult.java index 662e30bb..3bc6a2b4 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundQueryResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundQueryResult.java @@ -1,10 +1,14 @@ package com.github.binarywang.wxpay.bean.result; +import java.util.List; + import com.google.common.collect.Lists; import com.thoughtworks.xstream.annotations.XStreamAlias; -import lombok.*; - -import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; /** *
@@ -168,6 +172,9 @@ public class WxPayRefundQueryResult extends BaseWxPayResult {
     }
   }
 
+  /**
+   * The type Refund record.
+   */
   @Data
   @Builder(builderMethodName = "newBuilder")
   @NoArgsConstructor
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResult.java
index 9c7e0ad0..18ce1fc8 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResult.java
@@ -1,14 +1,14 @@
 package com.github.binarywang.wxpay.bean.result;
 
+import java.io.Serializable;
+import java.util.List;
+
 import com.google.common.collect.Lists;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 
-import java.io.Serializable;
-import java.util.List;
-
 /**
  * 
  * 微信支付-申请退款返回结果.
@@ -101,6 +101,19 @@ public class WxPayRefundResult extends BaseWxPayResult implements Serializable {
   @XStreamAlias("coupon_refund_count")
   private Integer couponRefundCount;
 
+  /**
+   * 
+   * 字段名:代金券退款总金额.
+   * 变量名:coupon_refund_fee
+   * 是否必填:否
+   * 类型:Int
+   * 示例值:100
+   * 描述:代金券退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为现金,说明详见代金券或立减优惠
+   * 
+ */ + @XStreamAlias("coupon_refund_fee") + private Integer couponRefundFee; + private List refundCoupons; /** @@ -108,7 +121,13 @@ public class WxPayRefundResult extends BaseWxPayResult implements Serializable { */ public void composeRefundCoupons() { List coupons = Lists.newArrayList(); - for (int i = 0; i < this.getCouponRefundCount(); i++) { + Integer refundCount = this.getCouponRefundCount(); + if (refundCount == null) { + //无退款代金券信息 + return; + } + + for (int i = 0; i < refundCount; i++) { coupons.add( new WxPayRefundCouponInfo( this.getXmlValue("xml/coupon_refund_id_" + i), @@ -117,6 +136,7 @@ public class WxPayRefundResult extends BaseWxPayResult implements Serializable { ) ); } + this.setRefundCoupons(coupons); } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java index cf37fa92..e35d0b25 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java @@ -95,6 +95,9 @@ public class WxPayConfig { /** * 初始化ssl. + * + * @return the ssl context + * @throws WxPayException the wx pay exception */ public SSLContext initSSLContext() throws WxPayException { if (StringUtils.isBlank(this.getMchId())) { diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java index 9dbe9d05..01753c0e 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java @@ -1,11 +1,10 @@ package com.github.binarywang.wxpay.constant; -import java.text.Format; -import java.util.List; - +import com.google.common.collect.Lists; import org.apache.commons.lang3.time.FastDateFormat; -import com.google.common.collect.Lists; +import java.text.Format; +import java.util.List; /** *
@@ -106,12 +105,39 @@ public class WxPayConstants {
     public static final String MICROPAY = "MICROPAY";
   }
 
+  /**
+   * 账户类型
+   */
+  public static class AccountType{
+    /**
+     * 基本账户
+     */
+    public static final String BASIC = "Basic";
+    /**
+     * 运营账户
+     */
+    public static final String OPERATION = "Operation";
+    /**
+     * Fees
+     */
+    public static final String FEES = "Fees";
+  }
+
   /**
    * 签名类型.
    */
   public static class SignType {
+    /**
+     * The constant HMAC_SHA256.
+     */
     public static final String HMAC_SHA256 = "HMAC-SHA256";
+    /**
+     * The constant MD5.
+     */
     public static final String MD5 = "MD5";
+    /**
+     * The constant ALL_SIGN_TYPES.
+     */
     public static final List ALL_SIGN_TYPES = Lists.newArrayList(HMAC_SHA256, MD5);
   }
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java
index 2d703480..cc8a80da 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java
@@ -1,5 +1,14 @@
 package com.github.binarywang.wxpay.converter;
 
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+
 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyCoupon;
 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
 import com.google.common.base.Function;
@@ -13,20 +22,20 @@ import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
 import com.thoughtworks.xstream.mapper.Mapper;
-import org.apache.commons.lang3.StringUtils;
-
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
 
 /**
+ * The type Wxpay order notify result converter.
+ *
  * @author aimilin
  */
 public class WxPayOrderNotifyResultConverter extends AbstractReflectionConverter {
 
+  /**
+   * Instantiates a new Wx pay order notify result converter.
+   *
+   * @param mapper             the mapper
+   * @param reflectionProvider the reflection provider
+   */
   public WxPayOrderNotifyResultConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
     super(mapper, reflectionProvider);
   }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java
index 945fca6c..a5a2552b 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java
@@ -51,11 +51,22 @@ public class WxPayException extends Exception {
    */
   private String xmlString;
 
+  /**
+   * Instantiates a new Wx pay exception.
+   *
+   * @param customErrorMsg the custom error msg
+   */
   public WxPayException(String customErrorMsg) {
     super(customErrorMsg);
     this.customErrorMsg = customErrorMsg;
   }
 
+  /**
+   * Instantiates a new Wx pay exception.
+   *
+   * @param customErrorMsg the custom error msg
+   * @param tr             the tr
+   */
   public WxPayException(String customErrorMsg, Throwable tr) {
     super(customErrorMsg, tr);
     this.customErrorMsg = customErrorMsg;
@@ -73,6 +84,9 @@ public class WxPayException extends Exception {
 
   /**
    * 通过BaseWxPayResult生成异常对象.
+   *
+   * @param payBaseResult the pay base result
+   * @return the wx pay exception
    */
   public static WxPayException from(BaseWxPayResult payBaseResult) {
     return WxPayException.newBuilder()
@@ -85,10 +99,18 @@ public class WxPayException extends Exception {
       .build();
   }
 
+  /**
+   * New builder builder.
+   *
+   * @return the builder
+   */
   public static Builder newBuilder() {
     return new Builder();
   }
 
+  /**
+   * The type Builder.
+   */
   public static final class Builder {
     private String returnCode;
     private String returnMsg;
@@ -100,40 +122,86 @@ public class WxPayException extends Exception {
     private Builder() {
     }
 
+    /**
+     * Return code builder.
+     *
+     * @param returnCode the return code
+     * @return the builder
+     */
     public Builder returnCode(String returnCode) {
       this.returnCode = returnCode;
       return this;
     }
 
+    /**
+     * Return msg builder.
+     *
+     * @param returnMsg the return msg
+     * @return the builder
+     */
     public Builder returnMsg(String returnMsg) {
       this.returnMsg = returnMsg;
       return this;
     }
 
+    /**
+     * Result code builder.
+     *
+     * @param resultCode the result code
+     * @return the builder
+     */
     public Builder resultCode(String resultCode) {
       this.resultCode = resultCode;
       return this;
     }
 
+    /**
+     * Err code builder.
+     *
+     * @param errCode the err code
+     * @return the builder
+     */
     public Builder errCode(String errCode) {
       this.errCode = errCode;
       return this;
     }
 
+    /**
+     * Err code des builder.
+     *
+     * @param errCodeDes the err code des
+     * @return the builder
+     */
     public Builder errCodeDes(String errCodeDes) {
       this.errCodeDes = errCodeDes;
       return this;
     }
 
+    /**
+     * Xml string builder.
+     *
+     * @param xmlString the xml string
+     * @return the builder
+     */
     public Builder xmlString(String xmlString) {
       this.xmlString = xmlString;
       return this;
     }
 
+    /**
+     * Build wx pay exception.
+     *
+     * @return the wx pay exception
+     */
     public WxPayException build() {
       return new WxPayException(this);
     }
 
+    /**
+     * Build error msg string.
+     *
+     * @return the string
+     */
     public String buildErrorMsg() {
       return Joiner.on(",").skipNulls().join(
         returnCode == null ? null : String.format("返回代码:[%s]", returnCode),
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EntPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EntPayService.java
index 4ab7f31b..43162f79 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EntPayService.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EntPayService.java
@@ -24,6 +24,8 @@ public interface EntPayService {
    * 
* * @param request 请求对象 + * @return the ent pay result + * @throws WxPayException the wx pay exception */ EntPayResult entPay(EntPayRequest request) throws WxPayException; @@ -36,6 +38,8 @@ public interface EntPayService { *
* * @param partnerTradeNo 商户订单号 + * @return the ent pay query result + * @throws WxPayException the wx pay exception */ EntPayQueryResult queryEntPay(String partnerTradeNo) throws WxPayException; @@ -54,6 +58,9 @@ public interface EntPayService { * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_7&index=4 * 接口链接:https://fraud.mch.weixin.qq.com/risk/getpublickey *
+ * + * @return the public key + * @throws WxPayException the wx pay exception */ String getPublicKey() throws WxPayException; @@ -67,6 +74,8 @@ public interface EntPayService { *
* * @param request 请求对象 + * @return the ent pay bank result + * @throws WxPayException the wx pay exception */ EntPayBankResult payBank(EntPayBankRequest request) throws WxPayException; @@ -79,6 +88,8 @@ public interface EntPayService { *
* * @param partnerTradeNo 商户订单号 + * @return the ent pay bank query result + * @throws WxPayException the wx pay exception */ EntPayBankQueryResult queryPayBank(String partnerTradeNo) throws WxPayException; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index d13d2737..7e2dff7b 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -1,19 +1,46 @@ package com.github.binarywang.wxpay.service; +import java.io.File; +import java.util.Date; +import java.util.Map; + import com.github.binarywang.wxpay.bean.WxPayApiData; -import com.github.binarywang.wxpay.bean.coupon.*; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponInfoQueryRequest; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponInfoQueryResult; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponStockQueryRequest; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponStockQueryResult; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; import com.github.binarywang.wxpay.bean.notify.WxScanPayNotifyResult; -import com.github.binarywang.wxpay.bean.request.*; -import com.github.binarywang.wxpay.bean.result.*; +import com.github.binarywang.wxpay.bean.request.WxPayAuthcode2OpenidRequest; +import com.github.binarywang.wxpay.bean.request.WxPayDownloadBillRequest; +import com.github.binarywang.wxpay.bean.request.WxPayDownloadFundFlowRequest; +import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest; +import com.github.binarywang.wxpay.bean.request.WxPayOrderCloseRequest; +import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest; +import com.github.binarywang.wxpay.bean.request.WxPayOrderReverseRequest; +import com.github.binarywang.wxpay.bean.request.WxPayRefundQueryRequest; +import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest; +import com.github.binarywang.wxpay.bean.request.WxPayReportRequest; +import com.github.binarywang.wxpay.bean.request.WxPaySendRedpackRequest; +import com.github.binarywang.wxpay.bean.request.WxPayShorturlRequest; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.bean.result.WxPayBillResult; +import com.github.binarywang.wxpay.bean.result.WxPayFundFlowResult; +import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult; +import com.github.binarywang.wxpay.bean.result.WxPayOrderCloseResult; +import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult; +import com.github.binarywang.wxpay.bean.result.WxPayOrderReverseResult; +import com.github.binarywang.wxpay.bean.result.WxPayRedpackQueryResult; +import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult; +import com.github.binarywang.wxpay.bean.result.WxPayRefundResult; +import com.github.binarywang.wxpay.bean.result.WxPaySendRedpackResult; +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult; import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.exception.WxPayException; -import java.io.File; -import java.util.Date; -import java.util.Map; - /** *
  * 微信支付相关接口.
@@ -26,6 +53,8 @@ public interface WxPayService {
 
   /**
    * 获取微信支付请求url前缀,沙箱环境可能不一样.
+   *
+   * @return the pay base url
    */
   String getPayBaseUrl();
 
@@ -35,7 +64,8 @@ public interface WxPayService {
    * @param url        请求地址
    * @param requestStr 请求信息
    * @param useKey     是否使用证书
-   * @return 返回请求结果字节数组
+   * @return 返回请求结果字节数组 byte [ ]
+   * @throws WxPayException the wx pay exception
    */
   byte[] postForBytes(String url, String requestStr, boolean useKey) throws WxPayException;
 
@@ -45,17 +75,22 @@ public interface WxPayService {
    * @param url        请求地址
    * @param requestStr 请求信息
    * @param useKey     是否使用证书
-   * @return 返回请求结果字符串
+   * @return 返回请求结果字符串 string
+   * @throws WxPayException the wx pay exception
    */
   String post(String url, String requestStr, boolean useKey) throws WxPayException;
 
   /**
    * 获取企业付款服务类.
+   *
+   * @return the ent pay service
    */
   EntPayService getEntPayService();
 
   /**
    * 设置企业付款服务类,允许开发者自定义实现类.
+   *
+   * @param entPayService the ent pay service
    */
   void setEntPayService(EntPayService entPayService);
 
@@ -74,6 +109,8 @@ public interface WxPayService {
    *
    * @param transactionId 微信订单号
    * @param outTradeNo    商户系统内部的订单号,当没提供transactionId时需要传这个。
+   * @return the wx pay order query result
+   * @throws WxPayException the wx pay exception
    */
   WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxPayException;
 
@@ -91,6 +128,8 @@ public interface WxPayService {
    * 
* * @param request 查询订单请求对象 + * @return the wx pay order query result + * @throws WxPayException the wx pay exception */ WxPayOrderQueryResult queryOrder(WxPayOrderQueryRequest request) throws WxPayException; @@ -107,6 +146,8 @@ public interface WxPayService { *
* * @param outTradeNo 商户系统内部的订单号 + * @return the wx pay order close result + * @throws WxPayException the wx pay exception */ WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException; @@ -123,15 +164,18 @@ public interface WxPayService { *
* * @param request 关闭订单请求对象 + * @return the wx pay order close result + * @throws WxPayException the wx pay exception */ WxPayOrderCloseResult closeOrder(WxPayOrderCloseRequest request) throws WxPayException; /** * 调用统一下单接口,并组装生成支付所需参数对象. * - * @param request 统一下单请求参数 * @param 请使用{@link com.github.binarywang.wxpay.bean.order}包下的类 + * @param request 统一下单请求参数 * @return 返回 {@link com.github.binarywang.wxpay.bean.order}包下的类对象 + * @throws WxPayException the wx pay exception */ T createOrder(WxPayUnifiedOrderRequest request) throws WxPayException; @@ -141,6 +185,8 @@ public interface WxPayService { * 接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder * * @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置) + * @return the wx pay unified order result + * @throws WxPayException the wx pay exception */ WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxPayException; @@ -149,6 +195,8 @@ public interface WxPayService { * 详见https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5 * * @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置) + * @return the pay info + * @throws WxPayException the wx pay exception * @deprecated 建议使用 {@link com.github.binarywang.wxpay.service.WxPayService#createOrder(WxPayUnifiedOrderRequest)} */ @Deprecated @@ -156,11 +204,15 @@ public interface WxPayService { /** * 获取配置. + * + * @return the config */ WxPayConfig getConfig(); /** * 设置配置对象. + * + * @param config the config */ void setConfig(WxPayConfig config); @@ -172,7 +224,8 @@ public interface WxPayService { *
* * @param request 请求对象 - * @return 退款操作结果 + * @return 退款操作结果 wx pay refund result + * @throws WxPayException the wx pay exception */ WxPayRefundResult refund(WxPayRefundRequest request) throws WxPayException; @@ -191,7 +244,8 @@ public interface WxPayService { * @param outTradeNo 商户订单号 * @param outRefundNo 商户退款单号 * @param refundId 微信退款单号 - * @return 退款信息 + * @return 退款信息 wx pay refund query result + * @throws WxPayException the wx pay exception */ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId) throws WxPayException; @@ -207,25 +261,38 @@ public interface WxPayService { *
* * @param request 微信退款单号 - * @return 退款信息 + * @return 退款信息 wx pay refund query result + * @throws WxPayException the wx pay exception */ WxPayRefundQueryResult refundQuery(WxPayRefundQueryRequest request) throws WxPayException; /** * 解析支付结果通知. * 详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7 + * + * @param xmlData the xml data + * @return the wx pay order notify result + * @throws WxPayException the wx pay exception */ WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData) throws WxPayException; /** * 解析退款结果通知 * 详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_16&index=9 + * + * @param xmlData the xml data + * @return the wx pay refund notify result + * @throws WxPayException the wx pay exception */ WxPayRefundNotifyResult parseRefundNotifyResult(String xmlData) throws WxPayException; /** * 解析扫码支付回调通知 * 详见https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4 + * + * @param xmlData the xml data + * @return the wx scan pay notify result + * @throws WxPayException the wx pay exception */ WxScanPayNotifyResult parseScanPayNotifyResult(String xmlData) throws WxPayException; @@ -240,6 +307,8 @@ public interface WxPayService { *
* * @param request 请求对象 + * @return the wx pay send redpack result + * @throws WxPayException the wx pay exception */ WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxPayException; @@ -253,6 +322,8 @@ public interface WxPayService { *
* * @param mchBillNo 商户发放红包的商户订单号,比如10000098201411111234567890 + * @return the wx pay redpack query result + * @throws WxPayException the wx pay exception */ WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayException; @@ -266,9 +337,9 @@ public interface WxPayService { *
* * @param productId 产品Id - * @param sideLength 要生成的二维码的边长,如果为空,则取默认值400 * @param logoFile 商户logo图片的文件对象,可以为空 - * @return 生成的二维码的字节数组 + * @param sideLength 要生成的二维码的边长,如果为空,则取默认值400 + * @return 生成的二维码的字节数组 byte [ ] */ byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength); @@ -282,7 +353,7 @@ public interface WxPayService { *
* * @param productId 产品Id - * @return 生成的二维码URL连接 + * @return 生成的二维码URL连接 string */ String createScanPayQrcodeMode1(String productId); @@ -297,7 +368,7 @@ public interface WxPayService { * @param codeUrl 微信返回的交易会话的二维码链接 * @param logoFile 商户logo图片的文件对象,可以为空 * @param sideLength 要生成的二维码的边长,如果为空,则取默认值400 - * @return 生成的二维码的字节数组 + * @return 生成的二维码的字节数组 byte [ ] */ byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength); @@ -311,6 +382,9 @@ public interface WxPayService { * 接口地址: https://api.mch.weixin.qq.com/payitil/report * 是否需要证书:不需要 *
+ * + * @param request the request + * @throws WxPayException the wx pay exception */ void report(WxPayReportRequest request) throws WxPayException; @@ -331,7 +405,8 @@ public interface WxPayService { * @param billType 账单类型 bill_type ALL,返回当日所有订单信息,默认值,SUCCESS,返回当日成功支付的订单,REFUND,返回当日退款订单 * @param tarType 压缩账单 tar_type 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。 * @param deviceInfo 设备号 device_info 非必传参数,终端设备号 - * @return 保存到本地的临时文件 + * @return WxPayBillResult对象 wx pay bill result + * @throws WxPayException the wx pay exception */ WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxPayException; @@ -349,10 +424,49 @@ public interface WxPayService { *
* * @param request 下载对账单请求 - * @return 保存到本地的临时文件 + * @return WxPayBillResult对象 wx pay bill result + * @throws WxPayException the wx pay exception */ WxPayBillResult downloadBill(WxPayDownloadBillRequest request) throws WxPayException; + /** + *
+   * 下载资金账单.
+   * 商户可以通过该接口下载自2017年6月1日起 的历史资金流水账单。
+   * 注意:
+   * 1、资金账单中的数据反映的是商户微信账户资金变动情况;
+   * 2、当日账单在次日上午9点开始生成,建议商户在上午10点以后获取;
+   * 3、资金账单中涉及金额的字段单位为“元”。
+   * 接口链接:https://api.mch.weixin.qq.com/pay/downloadfundflow
+   * 详情请见: 下载对账单
+   * 
+ * + * @param billDate 资金账单日期 bill_date 下载对账单的日期,格式:20140603 + * @param accountType 资金账户类型 account_type Basic,基本账户,Operation,运营账户,Fees,手续费账户 + * @param tarType 压缩账单 tar_type 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。 + * @return WxPayFundFlowResult对象 wx pay fund flow result + * @throws WxPayException the wx pay exception + */ + WxPayFundFlowResult downloadFundFlow(String billDate, String accountType, String tarType) throws WxPayException; + + /** + *
+   * 下载资金账单.
+   * 商户可以通过该接口下载自2017年6月1日起 的历史资金流水账单。
+   * 注意:
+   * 1、资金账单中的数据反映的是商户微信账户资金变动情况;
+   * 2、当日账单在次日上午9点开始生成,建议商户在上午10点以后获取;
+   * 3、资金账单中涉及金额的字段单位为“元”。
+   * 接口链接:https://api.mch.weixin.qq.com/pay/downloadfundflow
+   * 详情请见: 下载对账单
+   * 
+ * + * @param request 下载资金流水请求 + * @return WxPayFundFlowResult对象 wx pay fund flow result + * @throws WxPayException the wx pay exception + */ + WxPayFundFlowResult downloadFundFlow(WxPayDownloadFundFlowRequest request) throws WxPayException; + /** *
    * 提交刷卡支付.
@@ -364,6 +478,10 @@ public interface WxPayService {
    * 接口地址:   https://api.mch.weixin.qq.com/pay/micropay
    * 是否需要证书:不需要。
    * 
+ * + * @param request the request + * @return the wx pay micropay result + * @throws WxPayException the wx pay exception */ WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayException; @@ -380,6 +498,10 @@ public interface WxPayService { * 接口链接 :https://api.mch.weixin.qq.com/secapi/pay/reverse * 是否需要证书:请求需要双向证书。 *
+ * + * @param request the request + * @return the wx pay order reverse result + * @throws WxPayException the wx pay exception */ WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxPayException; @@ -395,6 +517,8 @@ public interface WxPayService { *
* * @param request 请求对象 + * @return the string + * @throws WxPayException the wx pay exception */ String shorturl(WxPayShorturlRequest request) throws WxPayException; @@ -404,7 +528,9 @@ public interface WxPayService { *
* * @param longUrl 需要被压缩的网址 - * @see WxPayService#shorturl(WxPayShorturlRequest) + * @return the string + * @throws WxPayException the wx pay exception + * @see WxPayService#shorturl(WxPayShorturlRequest) WxPayService#shorturl(WxPayShorturlRequest) */ String shorturl(String longUrl) throws WxPayException; @@ -419,7 +545,8 @@ public interface WxPayService { *
* * @param request 请求对象 - * @return openid + * @return openid string + * @throws WxPayException the wx pay exception */ String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxPayException; @@ -429,8 +556,9 @@ public interface WxPayService { *
* * @param authCode 授权码 - * @return openid - * @see WxPayService#authcode2Openid(WxPayAuthcode2OpenidRequest) + * @return openid string + * @throws WxPayException the wx pay exception + * @see WxPayService#authcode2Openid(WxPayAuthcode2OpenidRequest) WxPayService#authcode2Openid(WxPayAuthcode2OpenidRequest) */ String authcode2Openid(String authCode) throws WxPayException; @@ -442,6 +570,9 @@ public interface WxPayService { * 请求方式: POST * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_1 *
+ * + * @return the sandbox sign key + * @throws WxPayException the wx pay exception */ String getSandboxSignKey() throws WxPayException; @@ -452,6 +583,10 @@ public interface WxPayService { * 是否需要证书:请求需要双向证书。 * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_3 *
+ * + * @param request the request + * @return the wx pay coupon send result + * @throws WxPayException the wx pay exception */ WxPayCouponSendResult sendCoupon(WxPayCouponSendRequest request) throws WxPayException; @@ -461,6 +596,10 @@ public interface WxPayService { * 接口请求链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/query_coupon_stock * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_4 *
+ * + * @param request the request + * @return the wx pay coupon stock query result + * @throws WxPayException the wx pay exception */ WxPayCouponStockQueryResult queryCouponStock(WxPayCouponStockQueryRequest request) throws WxPayException; @@ -470,11 +609,17 @@ public interface WxPayService { * 接口请求链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/querycouponsinfo * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_5 *
+ * + * @param request the request + * @return the wx pay coupon info query result + * @throws WxPayException the wx pay exception */ WxPayCouponInfoQueryResult queryCouponInfo(WxPayCouponInfoQueryRequest request) throws WxPayException; /** * 获取微信请求数据,方便接口调用方获取处理. + * + * @return the wx api data */ WxPayApiData getWxApiData(); @@ -494,7 +639,9 @@ public interface WxPayService { * @param beginDate 开始时间 * @param endDate 结束时间 * @param offset 位移 - * @param limit 条数 + * @param limit 条数,建议填null,否则接口会报签名错误 + * @return the string + * @throws WxPayException the wx pay exception */ String queryComment(Date beginDate, Date endDate, Integer offset, Integer limit) throws WxPayException; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java index c627dcae..591b4a24 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java @@ -1,8 +1,29 @@ package com.github.binarywang.wxpay.service.impl; +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipException; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.github.binarywang.utils.qrcode.QrcodeUtils; import com.github.binarywang.wxpay.bean.WxPayApiData; -import com.github.binarywang.wxpay.bean.coupon.*; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponInfoQueryRequest; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponInfoQueryResult; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponStockQueryRequest; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponStockQueryResult; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; import com.github.binarywang.wxpay.bean.notify.WxScanPayNotifyResult; @@ -10,8 +31,40 @@ import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult; import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult; import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult; -import com.github.binarywang.wxpay.bean.request.*; -import com.github.binarywang.wxpay.bean.result.*; +import com.github.binarywang.wxpay.bean.request.WxPayAuthcode2OpenidRequest; +import com.github.binarywang.wxpay.bean.request.WxPayDefaultRequest; +import com.github.binarywang.wxpay.bean.request.WxPayDownloadBillRequest; +import com.github.binarywang.wxpay.bean.request.WxPayDownloadFundFlowRequest; +import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest; +import com.github.binarywang.wxpay.bean.request.WxPayOrderCloseRequest; +import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest; +import com.github.binarywang.wxpay.bean.request.WxPayOrderReverseRequest; +import com.github.binarywang.wxpay.bean.request.WxPayQueryCommentRequest; +import com.github.binarywang.wxpay.bean.request.WxPayRedpackQueryRequest; +import com.github.binarywang.wxpay.bean.request.WxPayRefundQueryRequest; +import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest; +import com.github.binarywang.wxpay.bean.request.WxPayReportRequest; +import com.github.binarywang.wxpay.bean.request.WxPaySendRedpackRequest; +import com.github.binarywang.wxpay.bean.request.WxPayShorturlRequest; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.bean.result.BaseWxPayResult; +import com.github.binarywang.wxpay.bean.result.WxPayAuthcode2OpenidResult; +import com.github.binarywang.wxpay.bean.result.WxPayBillBaseResult; +import com.github.binarywang.wxpay.bean.result.WxPayBillResult; +import com.github.binarywang.wxpay.bean.result.WxPayCommonResult; +import com.github.binarywang.wxpay.bean.result.WxPayFundFlowBaseResult; +import com.github.binarywang.wxpay.bean.result.WxPayFundFlowResult; +import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult; +import com.github.binarywang.wxpay.bean.result.WxPayOrderCloseResult; +import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult; +import com.github.binarywang.wxpay.bean.result.WxPayOrderReverseResult; +import com.github.binarywang.wxpay.bean.result.WxPayRedpackQueryResult; +import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult; +import com.github.binarywang.wxpay.bean.result.WxPayRefundResult; +import com.github.binarywang.wxpay.bean.result.WxPaySandboxSignKeyResult; +import com.github.binarywang.wxpay.bean.result.WxPaySendRedpackResult; +import com.github.binarywang.wxpay.bean.result.WxPayShorturlResult; +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult; import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.constant.WxPayConstants.BillType; import com.github.binarywang.wxpay.constant.WxPayConstants.SignType; @@ -23,17 +76,6 @@ import com.github.binarywang.wxpay.util.SignUtils; import com.google.common.base.Joiner; import com.google.common.collect.Maps; import jodd.io.ZipUtil; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; -import java.util.zip.ZipException; import static com.github.binarywang.wxpay.constant.WxPayConstants.QUERY_COMMENT_DATE_FORMAT; import static com.github.binarywang.wxpay.constant.WxPayConstants.TarType; @@ -48,11 +90,20 @@ import static com.github.binarywang.wxpay.constant.WxPayConstants.TarType; */ public abstract class BaseWxPayServiceImpl implements WxPayService { private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com"; + /** + * The Log. + */ protected final Logger log = LoggerFactory.getLogger(this.getClass()); + /** + * The constant wxApiData. + */ protected static ThreadLocal wxApiData = new ThreadLocal<>(); private EntPayService entPayService = new EntPayServiceImpl(this); + /** + * The Config. + */ protected WxPayConfig config; @Override @@ -291,7 +342,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { configMap.put("appid", appId); final WxPayAppOrderResult result = WxPayAppOrderResult.builder() - .sign(SignUtils.createSign(configMap, null, this.getConfig().getMchKey(), false)) + .sign(SignUtils.createSign(configMap, null, this.getConfig().getMchKey(), null)) .prepayId(prepayId) .partnerId(partnerId) .appId(appId) @@ -317,7 +368,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { .signType(signType) .build(); - payResult.setPaySign(SignUtils.createSign(payResult, signType, this.getConfig().getMchKey(), false)); + payResult.setPaySign(SignUtils.createSign(payResult, signType, this.getConfig().getMchKey(), null)); return (T) payResult; } @@ -368,7 +419,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { configMap.put("noncestr", nonceStr); configMap.put("appid", appId); // 此map用于客户端与微信服务器交互 - payInfo.put("sign", SignUtils.createSign(configMap, null, this.getConfig().getMchKey(), false)); + payInfo.put("sign", SignUtils.createSign(configMap, null, this.getConfig().getMchKey(), null)); payInfo.put("prepayId", prepayId); payInfo.put("partnerId", partnerId); payInfo.put("appId", appId); @@ -382,7 +433,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { payInfo.put("nonceStr", nonceStr); payInfo.put("package", "prepay_id=" + prepayId); payInfo.put("signType", SignType.MD5); - payInfo.put("paySign", SignUtils.createSign(payInfo, null, this.getConfig().getMchKey(), false)); + payInfo.put("paySign", SignUtils.createSign(payInfo, null, this.getConfig().getMchKey(), null)); } return payInfo; @@ -406,7 +457,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { params.put("time_stamp", String.valueOf(System.currentTimeMillis() / 1000)); params.put("nonce_str", String.valueOf(System.currentTimeMillis())); - String sign = SignUtils.createSign(params, null, this.getConfig().getMchKey(), false); + String sign = SignUtils.createSign(params, null, this.getConfig().getMchKey(), null); params.put("sign", sign); for (String key : params.keySet()) { @@ -581,6 +632,125 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { return wxPayBillResult; } + @Override + public WxPayFundFlowResult downloadFundFlow(String billDate, String accountType, String tarType) throws WxPayException { + + WxPayDownloadFundFlowRequest request = new WxPayDownloadFundFlowRequest(); + request.setBillDate(billDate); + request.setAccountType(accountType); + request.setTarType(tarType); + + return this.downloadFundFlow(request); + } + + @Override + public WxPayFundFlowResult downloadFundFlow(WxPayDownloadFundFlowRequest request) throws WxPayException { + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/pay/downloadfundflow"; + + String responseContent; + if (TarType.GZIP.equals(request.getTarType())) { + responseContent = this.handleGzipFundFlow(url, request.toXML()); + } else { + responseContent = this.post(url, request.toXML(), true); + if (responseContent.startsWith("<")) { + throw WxPayException.from(BaseWxPayResult.fromXML(responseContent, WxPayCommonResult.class)); + } + } + + return this.handleFundFlow(responseContent); + } + + private String handleGzipFundFlow(String url, String requestStr) throws WxPayException { + try { + byte[] responseBytes = this.postForBytes(url, requestStr, true); + Path tempDirectory = Files.createTempDirectory("fundFlow"); + Path path = Paths.get(tempDirectory.toString(), System.currentTimeMillis() + ".gzip"); + Files.write(path, responseBytes); + + try { + List allLines = Files.readAllLines(ZipUtil.ungzip(path.toFile()).toPath(), StandardCharsets.UTF_8); + return Joiner.on("\n").join(allLines); + } catch (ZipException e) { + if (e.getMessage().contains("Not in GZIP format")) { + throw WxPayException.from(BaseWxPayResult.fromXML(new String(responseBytes, StandardCharsets.UTF_8), + WxPayCommonResult.class)); + } else { + this.log.error("解压zip文件出错", e); + throw new WxPayException("解压zip文件出错"); + } + } + } catch (WxPayException wxPayException) { + throw wxPayException; + } catch (Exception e) { + this.log.error("解析对账单文件时出错", e); + throw new WxPayException("解压zip文件出错"); + } + } + + private WxPayFundFlowResult handleFundFlow(String responseContent) { + WxPayFundFlowResult wxPayFundFlowResult = new WxPayFundFlowResult(); + + String listStr = ""; + String objStr = ""; + + if (StringUtils.isNotBlank(responseContent) && responseContent.contains("资金流水总笔数")) { + listStr = responseContent.substring(0, responseContent.indexOf("资金流水总笔数")); + objStr = responseContent.substring(responseContent.indexOf("资金流水总笔数")); + } + /* + * 记账时间:2018-02-01 04:21:23 微信支付业务单号:50000305742018020103387128253 资金流水单号:1900009231201802015884652186 业务名称:退款 + * 业务类型:退款 收支类型:支出 收支金额(元):0.02 账户结余(元):0.17 资金变更提交申请人:system 备注:缺货 业务凭证号:REF4200000068201801293084726067 + * 参考以上格式进行取值 + */ + List wxPayFundFlowBaseResultList = new LinkedList<>(); + // 去空格 + String newStr = listStr.replaceAll(",", " "); + // 数据分组 + String[] tempStr = newStr.split("`"); + // 分组标题 + String[] t = tempStr[0].split(" "); + // 计算循环次数 + int j = tempStr.length / t.length; + // 纪录数组下标 + int k = 1; + for (int i = 0; i < j; i++) { + WxPayFundFlowBaseResult wxPayFundFlowBaseResult = new WxPayFundFlowBaseResult(); + + wxPayFundFlowBaseResult.setBillingTime(tempStr[k].trim()); + wxPayFundFlowBaseResult.setBizTransactionId(tempStr[k + 1].trim()); + wxPayFundFlowBaseResult.setFundFlowId(tempStr[k + 2].trim()); + wxPayFundFlowBaseResult.setBizName(tempStr[k + 3].trim()); + wxPayFundFlowBaseResult.setBizType(tempStr[k + 4].trim()); + wxPayFundFlowBaseResult.setFinancialType(tempStr[k + 5].trim()); + wxPayFundFlowBaseResult.setFinancialFee(tempStr[k + 6].trim()); + wxPayFundFlowBaseResult.setAccountBalance(tempStr[k + 7].trim()); + wxPayFundFlowBaseResult.setFundApplicant(tempStr[k + 8].trim()); + wxPayFundFlowBaseResult.setMemo(tempStr[k + 9].trim()); + wxPayFundFlowBaseResult.setBizVoucherId(tempStr[k + 10].trim()); + + wxPayFundFlowBaseResultList.add(wxPayFundFlowBaseResult); + k += t.length; + } + wxPayFundFlowResult.setWxPayFundFlowBaseResultList(wxPayFundFlowBaseResultList); + + /* + * 资金流水总笔数,收入笔数,收入金额,支出笔数,支出金额 `20.0,`17.0,`0.35,`3.0,`0.18 + * 参考以上格式进行取值 + */ + String totalStr = objStr.replaceAll(",", " "); + String[] totalTempStr = totalStr.split("`"); + wxPayFundFlowResult.setTotalRecord(totalTempStr[1]); + wxPayFundFlowResult.setIncomeRecord(totalTempStr[2]); + wxPayFundFlowResult.setIncomeAmount(totalTempStr[3]); + wxPayFundFlowResult.setExpenditureRecord(totalTempStr[4]); + wxPayFundFlowResult.setExpenditureAmount(totalTempStr[5]); + + return wxPayFundFlowResult; + + } + @Override public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java index b50a0786..5be2113b 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java @@ -1,19 +1,5 @@ package com.github.binarywang.wxpay.service.impl; -import com.github.binarywang.wxpay.bean.entpay.*; -import com.github.binarywang.wxpay.bean.request.WxPayDefaultRequest; -import com.github.binarywang.wxpay.bean.result.BaseWxPayResult; -import com.github.binarywang.wxpay.exception.WxPayException; -import com.github.binarywang.wxpay.service.EntPayService; -import com.github.binarywang.wxpay.service.WxPayService; -import com.github.binarywang.wxpay.util.SignUtils; -import org.apache.commons.codec.binary.Base64; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; - -import javax.crypto.Cipher; import java.io.File; import java.io.FileReader; import java.io.IOException; @@ -21,6 +7,28 @@ import java.nio.file.Files; import java.nio.file.Path; import java.security.PublicKey; import java.security.Security; +import javax.crypto.Cipher; + +import org.apache.commons.codec.binary.Base64; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; + +import com.github.binarywang.wxpay.bean.entpay.EntPayBankQueryRequest; +import com.github.binarywang.wxpay.bean.entpay.EntPayBankQueryResult; +import com.github.binarywang.wxpay.bean.entpay.EntPayBankRequest; +import com.github.binarywang.wxpay.bean.entpay.EntPayBankResult; +import com.github.binarywang.wxpay.bean.entpay.EntPayQueryRequest; +import com.github.binarywang.wxpay.bean.entpay.EntPayQueryResult; +import com.github.binarywang.wxpay.bean.entpay.EntPayRequest; +import com.github.binarywang.wxpay.bean.entpay.EntPayResult; +import com.github.binarywang.wxpay.bean.entpay.GetPublicKeyResult; +import com.github.binarywang.wxpay.bean.request.WxPayDefaultRequest; +import com.github.binarywang.wxpay.bean.result.BaseWxPayResult; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.EntPayService; +import com.github.binarywang.wxpay.service.WxPayService; /** *
@@ -32,6 +40,11 @@ import java.security.Security;
 public class EntPayServiceImpl implements EntPayService {
   private WxPayService payService;
 
+  /**
+   * Instantiates a new Ent pay service.
+   *
+   * @param payService the pay service
+   */
   public EntPayServiceImpl(WxPayService payService) {
     this.payService = payService;
   }
@@ -65,8 +78,8 @@ public class EntPayServiceImpl implements EntPayService {
     WxPayDefaultRequest request = new WxPayDefaultRequest();
     request.setMchId(this.payService.getConfig().getMchId());
     request.setNonceStr(String.valueOf(System.currentTimeMillis()));
-    request.setSign(SignUtils.createSign(request, null, this.payService.getConfig().getMchKey(),
-      true));
+
+    request.checkAndSign(this.payService.getConfig());
 
     String url = "https://fraud.mch.weixin.qq.com/risk/getpublickey";
     String responseContent = this.payService.post(url, request.toXML(), true);
@@ -132,6 +145,13 @@ public class EntPayServiceImpl implements EntPayService {
     }
   }
 
+  /**
+   * The entry point of application.
+   *
+   * @param args the input arguments
+   * @throws WxPayException the wx pay exception
+   * @throws IOException    the io exception
+   */
   public static void main(String[] args) throws WxPayException, IOException {
     String key = "-----BEGIN RSA PUBLIC KEY-----\n" +
       "MIIBCgKCAQEAtEeUSop/YGqZ53Y++R9NapFSZmorj+SL/brmJUU7+hyClEnPOeG/\n" +
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
index a6cb5620..753652f4 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
@@ -1,10 +1,10 @@
 package com.github.binarywang.wxpay.service.impl;
 
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.StandardCharsets;
-import javax.net.ssl.SSLContext;
-
+import com.github.binarywang.wxpay.bean.WxPayApiData;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import jodd.util.Base64;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpHost;
 import org.apache.http.auth.AuthScope;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.http.client.CredentialsProvider;
@@ -20,9 +20,9 @@ import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.util.EntityUtils;
 
-import com.github.binarywang.wxpay.bean.WxPayApiData;
-import com.github.binarywang.wxpay.exception.WxPayException;
-import jodd.util.Base64;
+import javax.net.ssl.SSLContext;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
 
 /**
  * 
@@ -83,7 +83,7 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
       return new StringEntity(new String(requestStr.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
     } catch (UnsupportedEncodingException e) {
       //cannot happen
-      this.log.error(e.getMessage(),e);
+      this.log.error(e.getMessage(), e);
       return null;
     }
   }
@@ -94,14 +94,13 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
       this.initSSLContext(httpClientBuilder);
     }
 
-    if (StringUtils.isNotBlank(this.getConfig().getHttpProxyHost())
-      && this.getConfig().getHttpProxyPort() > 0) {
+    if (StringUtils.isNotBlank(this.getConfig().getHttpProxyHost()) && this.getConfig().getHttpProxyPort() > 0) {
       // 使用代理服务器 需要用户认证的代理服务器
       CredentialsProvider provider = new BasicCredentialsProvider();
-      provider.setCredentials(
-        new AuthScope(this.getConfig().getHttpProxyHost(), this.getConfig().getHttpProxyPort()),
+      provider.setCredentials(new AuthScope(this.getConfig().getHttpProxyHost(), this.getConfig().getHttpProxyPort()),
         new UsernamePasswordCredentials(this.getConfig().getHttpProxyUsername(), this.getConfig().getHttpProxyPassword()));
       httpClientBuilder.setDefaultCredentialsProvider(provider);
+      httpClientBuilder.setProxy(new HttpHost(this.getConfig().getHttpProxyHost(), this.getConfig().getHttpProxyPort()));
     }
     return httpClientBuilder;
   }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java
index 2976e73f..1c7b315d 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java
@@ -1,5 +1,10 @@
 package com.github.binarywang.wxpay.service.impl;
 
+import java.nio.charset.StandardCharsets;
+import javax.net.ssl.SSLContext;
+
+import org.apache.commons.lang3.StringUtils;
+
 import com.github.binarywang.wxpay.bean.WxPayApiData;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import jodd.http.HttpConnectionProvider;
@@ -10,10 +15,6 @@ import jodd.http.ProxyInfo.ProxyType;
 import jodd.http.net.SSLSocketHttpConnectionProvider;
 import jodd.http.net.SocketHttpConnectionProvider;
 import jodd.util.Base64;
-import org.apache.commons.lang3.StringUtils;
-
-import javax.net.ssl.SSLContext;
-import java.nio.charset.StandardCharsets;
 
 /**
  * 微信支付请求实现类,jodd-http实现.
@@ -87,7 +88,7 @@ public class WxPayServiceJoddHttpImpl extends BaseWxPayServiceImpl {
     try {
       this.log.debug("【微信服务器响应头信息】:\n{}", response.toString(false));
     } catch (NullPointerException e) {
-      throw new WxPayException("response.toString() 居然抛出空指针异常了", e);
+      this.log.warn("HttpResponse.toString() 居然抛出空指针异常了", e);
     }
 
     String responseString = response.bodyText();
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java
index 10aedfe3..2883c8b1 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java
@@ -1,25 +1,25 @@
 package com.github.binarywang.wxpay.util;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+
 import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
 import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
 import com.github.binarywang.wxpay.constant.WxPayConstants.SignType;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
-import me.chanjar.weixin.common.util.BeanUtils;
-import org.apache.commons.codec.binary.Hex;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.util.*;
+import lombok.extern.slf4j.Slf4j;
 
 /**
  * 
@@ -29,11 +29,14 @@ import java.util.*;
  *
  * @author binarywang(Binary Wang)
  */
+@Slf4j
 public class SignUtils {
-  private static final Logger log = LoggerFactory.getLogger(SignUtils.class);
-
   /**
-   * 请参考并使用 {@link #createSign(Object, String, String, boolean)}.
+   * 请参考并使用 {@link #createSign(Object, String, String, String[])}.
+   *
+   * @param xmlBean the xml bean
+   * @param signKey the sign key
+   * @return the string
    */
   @Deprecated
   public static String createSign(Object xmlBean, String signKey) {
@@ -41,45 +44,47 @@ public class SignUtils {
   }
 
   /**
-   * 请参考并使用 {@link #createSign(Map, String, String, boolean)}.
+   * 请参考并使用 {@link #createSign(Map, String, String, String[])} .
+   *
+   * @param params  the params
+   * @param signKey the sign key
+   * @return the string
    */
   @Deprecated
   public static String createSign(Map params, String signKey) {
-    return createSign(params, null, signKey, false);
+    return createSign(params, null, signKey, new String[0]);
   }
 
   /**
    * 微信支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3).
    *
-   * @param xmlBean          Bean里的属性如果存在XML注解,则使用其作为key,否则使用变量名
-   * @param signType         签名类型,如果为空,则默认为MD5
-   * @param signKey          签名Key
-   * @param isIgnoreSignType 签名时,是否忽略signType
-   * @return 签名字符串
+   * @param xmlBean       Bean里的属性如果存在XML注解,则使用其作为key,否则使用变量名
+   * @param signType      签名类型,如果为空,则默认为MD5
+   * @param signKey       签名Key
+   * @param ignoredParams 签名时需要忽略的特殊参数
+   * @return 签名字符串 string
    */
-  public static String createSign(Object xmlBean, String signType, String signKey, boolean isIgnoreSignType) {
-    return createSign(xmlBean2Map(xmlBean), signType, signKey, isIgnoreSignType);
+  public static String createSign(Object xmlBean, String signType, String signKey, String[] ignoredParams) {
+    return createSign(xmlBean2Map(xmlBean), signType, signKey, ignoredParams);
   }
 
   /**
    * 微信支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3).
    *
-   * @param params         参数信息
-   * @param signType       签名类型,如果为空,则默认为MD5
-   * @param signKey        签名Key
-   * @param ignoreSignType 签名时,是否忽略signType
-   * @return 签名字符串
+   * @param params        参数信息
+   * @param signType      签名类型,如果为空,则默认为MD5
+   * @param signKey       签名Key
+   * @param ignoredParams 签名时需要忽略的特殊参数
+   * @return 签名字符串 string
    */
-  public static String createSign(Map params, String signType, String signKey, boolean ignoreSignType) {
+  public static String createSign(Map params, String signType, String signKey, String[] ignoredParams) {
     SortedMap sortedMap = new TreeMap<>(params);
 
     StringBuilder toSign = new StringBuilder();
     for (String key : sortedMap.keySet()) {
       String value = params.get(key);
       boolean shouldSign = false;
-      if (ignoreSignType && "sign_type".equals(key)) {
-        shouldSign = false;
-      } else if (StringUtils.isNotEmpty(value)
+      if (StringUtils.isNotEmpty(value) && !ArrayUtils.contains(ignoredParams, key)
         && !Lists.newArrayList("sign", "key", "xmlString", "xmlDoc", "couponList").contains(key)) {
         shouldSign = true;
       }
@@ -91,26 +96,12 @@ public class SignUtils {
 
     toSign.append("key=").append(signKey);
     if (SignType.HMAC_SHA256.equals(signType)) {
-      return createHmacSha256Sign(toSign.toString(), signKey);
+      return me.chanjar.weixin.common.util.SignUtils.createHmacSha256Sign(toSign.toString(), signKey);
     } else {
       return DigestUtils.md5Hex(toSign.toString()).toUpperCase();
     }
   }
 
-  private static String createHmacSha256Sign(String message, String key) {
-    try {
-      Mac sha256 = Mac.getInstance("HmacSHA256");
-      SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "HmacSHA256");
-      sha256.init(secretKeySpec);
-      byte[] bytes = sha256.doFinal(message.getBytes());
-      return Hex.encodeHexString(bytes).toUpperCase();
-    } catch (NoSuchAlgorithmException | InvalidKeyException e) {
-      log.error(e.getMessage(), e);
-    }
-
-    return null;
-  }
-
   /**
    * 校验签名是否正确.
    *
@@ -132,25 +123,25 @@ public class SignUtils {
    * @return true - 签名校验成功,false - 签名校验失败
    */
   public static boolean checkSign(Map params, String signType, String signKey) {
-    String sign = createSign(params, signType, signKey, false);
+    String sign = createSign(params, signType, signKey, new String[0]);
     return sign.equals(params.get("sign"));
   }
 
   /**
-   * 将bean按照@XStreamAlias标识的字符串内容生成以之为key的map对象
+   * 将bean按照@XStreamAlias标识的字符串内容生成以之为key的map对象.
    *
    * @param bean 包含@XStreamAlias的xml bean对象
-   * @return map对象
+   * @return map对象 map
    */
   public static Map xmlBean2Map(Object bean) {
     Map result = Maps.newHashMap();
     List fields = new ArrayList<>(Arrays.asList(bean.getClass().getDeclaredFields()));
     fields.addAll(Arrays.asList(bean.getClass().getSuperclass().getDeclaredFields()));
-    if(bean.getClass().getSuperclass().getSuperclass() == BaseWxPayRequest.class){
+    if (bean.getClass().getSuperclass().getSuperclass() == BaseWxPayRequest.class) {
       fields.addAll(Arrays.asList(BaseWxPayRequest.class.getDeclaredFields()));
     }
 
-    if(bean.getClass().getSuperclass().getSuperclass() == BaseWxPayResult.class){
+    if (bean.getClass().getSuperclass().getSuperclass() == BaseWxPayResult.class) {
       fields.addAll(Arrays.asList(BaseWxPayResult.class.getDeclaredFields()));
     }
 
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResultTest.java
index 40446a29..a22916de 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResultTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResultTest.java
@@ -1,16 +1,19 @@
 package com.github.binarywang.wxpay.bean.notify;
 
-import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
 import org.testng.*;
 import org.testng.annotations.*;
 
 /**
  * 
  * Created by Binary Wang on 2017-6-15.
- * @author Binary Wang
  * 
+ * + * @author Binary Wang */ public class WxPayOrderNotifyResultTest { + /** + * Test from xml. + */ @Test public void testFromXML() { String xmlString = "\n" + diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java index cd1777f8..4b99b769 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java @@ -28,6 +28,11 @@ public class WxPayRefundNotifyResultTest { @Inject private WxPayConfig wxPayConfig; + /** + * Test from xml. + * + * @throws WxPayException the wx pay exception + */ public void testFromXML() throws WxPayException { String xmlString = "" + "SUCCESS" + @@ -42,6 +47,11 @@ public class WxPayRefundNotifyResultTest { System.out.println(refundNotifyResult); } + /** + * Encode req info. + * + * @throws Exception the exception + */ public void encodeReqInfo() throws Exception { String xml = "\n" + "\n" + diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxScanPayNotifyResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxScanPayNotifyResultTest.java index 77316724..04853e15 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxScanPayNotifyResultTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxScanPayNotifyResultTest.java @@ -16,10 +16,16 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class WxScanPayNotifyResultTest { + /** + * Test to map. + */ @Test public void testToMap() { } + /** + * Test from xml. + */ @Test public void testFromXML() { String xmlString = "\n" + diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResultTest.java index 10baf017..83fcc5f3 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResultTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResultTest.java @@ -1,26 +1,42 @@ package com.github.binarywang.wxpay.bean.result; +import java.util.Map; + import org.testng.*; import org.testng.annotations.*; -import java.util.Map; - /** *
  * Created by Binary Wang on 2017-01-04.
- * @author binarywang(Binary Wang)
  * 
+ * + * @author binarywang(Binary Wang) */ public class BaseWxPayResultTest { + /** + * Test get xml value. + * + * @throws Exception the exception + */ @Test public void testGetXmlValue() throws Exception { } + /** + * Test xml 2 doc. + * + * @throws Exception the exception + */ @Test public void testXml2Doc() throws Exception { } + /** + * Test to map. + * + * @throws Exception the exception + */ @Test public void testToMap() throws Exception { WxPayOrderQueryResult result = new WxPayOrderQueryResult(); @@ -53,6 +69,9 @@ public class BaseWxPayResultTest { } + /** + * Test to map with empty xml string. + */ @Test(expectedExceptions = {RuntimeException.class}) public void testToMap_with_empty_xmlString() { WxPayOrderQueryResult result = new WxPayOrderQueryResult(); diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryResultTest.java index 1925c80b..c930b7cc 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryResultTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryResultTest.java @@ -6,10 +6,14 @@ import org.testng.annotations.*; /** *
  * Created by Binary Wang on 2017-01-04.
+ *  
+ * * @author binarywang(Binary Wang) - *
*/ public class WxPayOrderQueryResultTest { + /** + * Test compose coupons. + */ @Test public void testComposeCoupons() { /* diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRedpackQueryResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRedpackQueryResultTest.java index c857fa0d..b771cbb1 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRedpackQueryResultTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRedpackQueryResultTest.java @@ -13,6 +13,9 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Binary Wang */ public class WxPayRedpackQueryResultTest { + /** + * Test from xml. + */ @Test public void testFromXML() { String xmlString = "\n" + diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRefundQueryResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRefundQueryResultTest.java index 6ca4192a..e9e8e80b 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRefundQueryResultTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRefundQueryResultTest.java @@ -7,10 +7,16 @@ import org.testng.annotations.*; /** *
  * Created by Binary Wang on 2016-12-29.
+ *  
+ * * @author binarywang(Binary Wang) - *
*/ public class WxPayRefundQueryResultTest { + /** + * Compose refund records. + * + * @throws Exception the exception + */ @Test public void composeRefundRecords() throws Exception { /* diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResultTest.java index 7c9b34fb..f4f87f40 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResultTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResultTest.java @@ -13,6 +13,9 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class WxPayRefundResultTest { + /** + * Test compose refund coupons. + */ @Test public void testComposeRefundCoupons() { /* diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPaySendRedpackResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPaySendRedpackResultTest.java index 1985c924..206703b8 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPaySendRedpackResultTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPaySendRedpackResultTest.java @@ -1,20 +1,30 @@ package com.github.binarywang.wxpay.bean.result; -import com.thoughtworks.xstream.XStream; -import me.chanjar.weixin.common.util.xml.XStreamInitializer; import org.testng.*; import org.testng.annotations.*; +import com.thoughtworks.xstream.XStream; +import me.chanjar.weixin.common.util.xml.XStreamInitializer; + +/** + * The type Wx pay send redpack result test. + */ public class WxPaySendRedpackResultTest { private XStream xstream; + /** + * Sets . + */ @BeforeTest public void setup() { this.xstream = XStreamInitializer.getInstance(); this.xstream.processAnnotations(WxPaySendRedpackResult.class); } + /** + * Load success result. + */ @Test public void loadSuccessResult() { final String successSample = "\n" + @@ -37,6 +47,9 @@ public class WxPaySendRedpackResultTest { Assert.assertEquals("20150520102602", wxMpRedpackResult.getSendTime()); } + /** + * Load failure result. + */ @Test public void loadFailureResult() { final String failureSample = "\n" + diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java index 83bcbf2c..3edc2c32 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java @@ -14,6 +14,11 @@ import static org.testng.Assert.*; public class WxPayConfigTest { private WxPayConfig payConfig = new WxPayConfig(); + /** + * Test init ssl context. + * + * @throws Exception the exception + */ @Test public void testInitSSLContext() throws Exception { payConfig.setMchId("123"); diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImplTest.java index 15cfdd82..13a507d9 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImplTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImplTest.java @@ -1,13 +1,44 @@ package com.github.binarywang.wxpay.service.impl; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Calendar; +import java.util.Date; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.*; + import com.github.binarywang.utils.qrcode.QrcodeUtils; -import com.github.binarywang.wxpay.bean.coupon.*; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponInfoQueryRequest; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponInfoQueryResult; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponStockQueryRequest; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponStockQueryResult; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; +import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResultTest; import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult; import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult; -import com.github.binarywang.wxpay.bean.request.*; -import com.github.binarywang.wxpay.bean.result.*; +import com.github.binarywang.wxpay.bean.request.WxPayAuthcode2OpenidRequest; +import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest; +import com.github.binarywang.wxpay.bean.request.WxPayOrderReverseRequest; +import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest; +import com.github.binarywang.wxpay.bean.request.WxPayReportRequest; +import com.github.binarywang.wxpay.bean.request.WxPaySendRedpackRequest; +import com.github.binarywang.wxpay.bean.request.WxPayShorturlRequest; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.bean.result.WxPayBillResult; +import com.github.binarywang.wxpay.bean.result.WxPayFundFlowResult; +import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult; +import com.github.binarywang.wxpay.bean.result.WxPayOrderReverseResult; +import com.github.binarywang.wxpay.bean.result.WxPayRedpackQueryResult; +import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult; +import com.github.binarywang.wxpay.bean.result.WxPayRefundResult; +import com.github.binarywang.wxpay.bean.result.WxPaySendRedpackResult; +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult; +import com.github.binarywang.wxpay.constant.WxPayConstants.AccountType; import com.github.binarywang.wxpay.constant.WxPayConstants.BillType; import com.github.binarywang.wxpay.constant.WxPayConstants.SignType; import com.github.binarywang.wxpay.constant.WxPayConstants.TradeType; @@ -16,14 +47,6 @@ import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.testbase.ApiTestModule; import com.github.binarywang.wxpay.testbase.XmlWxPayConfig; import com.google.inject.Inject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.annotations.*; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Calendar; -import java.util.Date; import static com.github.binarywang.wxpay.constant.WxPayConstants.TarType; import static org.assertj.core.api.Assertions.assertThat; @@ -45,6 +68,8 @@ public class BaseWxPayServiceImplTest { /** * Test method for {@link WxPayService#unifiedOrder(WxPayUnifiedOrderRequest)}. + * + * @throws WxPayException the wx pay exception */ @Test public void testUnifiedOrder() throws WxPayException { @@ -63,11 +88,21 @@ public class BaseWxPayServiceImplTest { this.logger.warn(this.payService.getWxApiData().toString()); } + /** + * Test create order. + * + * @throws Exception the exception + */ @Test public void testCreateOrder() throws Exception { //see other tests with method name starting with 'testCreateOrder_' } + /** + * Test create order jsapi. + * + * @throws Exception the exception + */ @Test public void testCreateOrder_jsapi() throws Exception { WxPayMpOrderResult result = this.payService @@ -84,6 +119,11 @@ public class BaseWxPayServiceImplTest { this.logger.warn(this.payService.getWxApiData().toString()); } + /** + * Test create order app. + * + * @throws Exception the exception + */ @Test public void testCreateOrder_app() throws Exception { WxPayAppOrderResult result = this.payService @@ -99,6 +139,11 @@ public class BaseWxPayServiceImplTest { this.logger.warn(this.payService.getWxApiData().toString()); } + /** + * Test create order native. + * + * @throws Exception the exception + */ @Test public void testCreateOrder_native() throws Exception { WxPayNativeOrderResult result = this.payService @@ -115,6 +160,11 @@ public class BaseWxPayServiceImplTest { this.logger.warn(this.payService.getWxApiData().toString()); } + /** + * Test get pay info. + * + * @throws Exception the exception + */ @Test public void testGetPayInfo() throws Exception { //please use createOrder instead @@ -122,6 +172,8 @@ public class BaseWxPayServiceImplTest { /** * Test method for {@link WxPayService#queryOrder(String, String)} . + * + * @throws WxPayException the wx pay exception */ @Test public void testQueryOrder() throws WxPayException { @@ -131,12 +183,19 @@ public class BaseWxPayServiceImplTest { /** * Test method for {@link WxPayService#closeOrder(String)} . + * + * @throws WxPayException the wx pay exception */ @Test public void testCloseOrder() throws WxPayException { this.logger.info(this.payService.closeOrder("11212121").toString()); } + /** + * Billing data object [ ] [ ]. + * + * @return the object [ ] [ ] + */ @DataProvider public Object[][] billingData() { return new Object[][]{ @@ -151,6 +210,15 @@ public class BaseWxPayServiceImplTest { }; } + /** + * Test download bill. + * + * @param billDate the bill date + * @param billType the bill type + * @param tarType the tar type + * @param deviceInfo the device info + * @throws Exception the exception + */ @Test(dataProvider = "billingData") public void testDownloadBill(String billDate, String billType, String tarType, String deviceInfo) throws Exception { @@ -159,12 +227,65 @@ public class BaseWxPayServiceImplTest { this.logger.info(billResult.toString()); } + /** + * Test download bill with no params. + * + * @throws Exception the exception + */ @Test(expectedExceptions = WxPayException.class) public void testDownloadBill_withNoParams() throws Exception { //必填字段为空时,抛出异常 this.payService.downloadBill("", "", "", null); } + /** + * Fund flow data object [ ] [ ]. + * + * @return the object [ ] [ ] + */ + @DataProvider + public Object[][] fundFlowData() { + return new Object[][]{ + {"20180819", AccountType.BASIC, TarType.GZIP}, + {"20180819", AccountType.OPERATION, TarType.GZIP}, + {"20180819", AccountType.FEES, TarType.GZIP}, + {"20180819", AccountType.BASIC, null}, + {"20180819", AccountType.OPERATION, null}, + {"20180819", AccountType.FEES, null} + }; + } + + /** + * Test download fund flow. + * + * @param billDate the bill date + * @param accountType the account type + * @param tarType the tar type + * @throws Exception the exception + */ + @Test(dataProvider = "fundFlowData") + public void testDownloadFundFlow(String billDate, String accountType, String tarType) throws Exception { + WxPayFundFlowResult fundFlowResult = this.payService.downloadFundFlow(billDate, accountType, tarType); + assertThat(fundFlowResult).isNotNull(); + this.logger.info(fundFlowResult.toString()); + } + + /** + * Test download fund flow with no params. + * + * @throws Exception the exception + */ + @Test(expectedExceptions = WxPayException.class) + public void testDownloadFundFlow_withNoParams() throws Exception { + //必填字段为空时,抛出异常 + this.payService.downloadFundFlow("", "", null); + } + + /** + * Test report. + * + * @throws Exception the exception + */ @Test public void testReport() throws Exception { WxPayReportRequest request = new WxPayReportRequest(); @@ -179,6 +300,8 @@ public class BaseWxPayServiceImplTest { /** * Test method for {@link WxPayService#refund(WxPayRefundRequest)} . + * + * @throws Exception the exception */ @Test public void testRefund() throws Exception { @@ -194,6 +317,8 @@ public class BaseWxPayServiceImplTest { /** * Test method for {@link WxPayService#refundQuery(String, String, String, String)} . + * + * @throws Exception the exception */ @Test public void testRefundQuery() throws Exception { @@ -216,6 +341,11 @@ public class BaseWxPayServiceImplTest { this.logger.info(result.toString()); } + /** + * Test parse refund notify result. + * + * @throws Exception the exception + */ @Test public void testParseRefundNotifyResult() throws Exception { // 请参考com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResultTest里的单元测试 @@ -223,6 +353,8 @@ public class BaseWxPayServiceImplTest { /** * Test method for {@link WxPayService#sendRedpack(WxPaySendRedpackRequest)} . + * + * @throws Exception the exception */ @Test public void testSendRedpack() throws Exception { @@ -241,6 +373,8 @@ public class BaseWxPayServiceImplTest { /** * Test method for {@link WxPayService#queryRedpack(String)}. + * + * @throws Exception the exception */ @Test public void testQueryRedpack() throws Exception { @@ -248,6 +382,11 @@ public class BaseWxPayServiceImplTest { this.logger.info(redpackResult.toString()); } + /** + * Test create scan pay qrcode mode 1. + * + * @throws Exception the exception + */ @Test public void testCreateScanPayQrcodeMode1() throws Exception { String productId = "abc"; @@ -261,6 +400,11 @@ public class BaseWxPayServiceImplTest { assertTrue(qrcodeContent.contains("product_id=" + productId)); } + /** + * Test create scan pay qrcode mode 2. + * + * @throws Exception the exception + */ @Test public void testCreateScanPayQrcodeMode2() throws Exception { String qrcodeContent = "abc"; @@ -270,6 +414,11 @@ public class BaseWxPayServiceImplTest { assertEquals(QrcodeUtils.decodeQrcode(qrcodeFilePath.toFile()), qrcodeContent); } + /** + * Test micropay. + * + * @throws Exception the exception + */ @Test public void testMicropay() throws Exception { WxPayMicropayResult result = this.payService.micropay( @@ -284,16 +433,31 @@ public class BaseWxPayServiceImplTest { this.logger.info(result.toString()); } + /** + * Test get config. + * + * @throws Exception the exception + */ @Test public void testGetConfig() throws Exception { // no need to test } + /** + * Test set config. + * + * @throws Exception the exception + */ @Test public void testSetConfig() throws Exception { // no need to test } + /** + * Test reverse order. + * + * @throws Exception the exception + */ @Test public void testReverseOrder() throws Exception { WxPayOrderReverseResult result = this.payService.reverseOrder( @@ -305,6 +469,11 @@ public class BaseWxPayServiceImplTest { this.logger.info(result.toString()); } + /** + * Test shorturl. + * + * @throws Exception the exception + */ @Test public void testShorturl() throws Exception { String longUrl = "weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX"; @@ -318,6 +487,11 @@ public class BaseWxPayServiceImplTest { this.logger.info(result); } + /** + * Test authcode 2 openid. + * + * @throws Exception the exception + */ @Test public void testAuthcode2Openid() throws Exception { String authCode = "11111"; @@ -331,6 +505,11 @@ public class BaseWxPayServiceImplTest { this.logger.info(result); } + /** + * Test get sandbox sign key. + * + * @throws Exception the exception + */ @Test public void testGetSandboxSignKey() throws Exception { final String signKey = this.payService.getSandboxSignKey(); @@ -338,6 +517,11 @@ public class BaseWxPayServiceImplTest { this.logger.info(signKey); } + /** + * Test send coupon. + * + * @throws Exception the exception + */ @Test public void testSendCoupon() throws Exception { WxPayCouponSendResult result = this.payService.sendCoupon(WxPayCouponSendRequest.newBuilder() @@ -349,6 +533,11 @@ public class BaseWxPayServiceImplTest { this.logger.info(result.toString()); } + /** + * Test query coupon stock. + * + * @throws Exception the exception + */ @Test public void testQueryCouponStock() throws Exception { WxPayCouponStockQueryResult result = this.payService.queryCouponStock( @@ -359,6 +548,11 @@ public class BaseWxPayServiceImplTest { this.logger.info(result.toString()); } + /** + * Test query coupon info. + * + * @throws Exception the exception + */ @Test public void testQueryCouponInfo() throws Exception { WxPayCouponInfoQueryResult result = this.payService.queryCouponInfo( @@ -373,6 +567,8 @@ public class BaseWxPayServiceImplTest { /** * 只支持拉取90天内的评论数据 + * + * @throws Exception the exception */ @Test public void testQueryComment() throws Exception { @@ -381,13 +577,15 @@ public class BaseWxPayServiceImplTest { Date endDate = calendar.getTime(); calendar.add(Calendar.DAY_OF_MONTH, -88); Date beginDate = calendar.getTime(); - String result = this.payService.queryComment(beginDate, endDate, 0, null); + String result = this.payService.queryComment(beginDate, endDate, 0, 1); this.logger.info(result); } /** - * @see {@link com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResultTest} - * @throws Exception + * Test parse order notify result. + * + * @throws Exception the exception + * @see WxPayOrderNotifyResultTest#testFromXML() WxPayOrderNotifyResultTest#testFromXML() */ @Test public void testParseOrderNotifyResult() throws Exception { @@ -424,6 +622,11 @@ public class BaseWxPayServiceImplTest { System.out.println(result); } + /** + * Test get wx api data. + * + * @throws Exception the exception + */ @Test public void testGetWxApiData() throws Exception { //see test in testUnifiedOrder() diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImplTest.java index b0d34a60..4c7f6e32 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImplTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImplTest.java @@ -28,6 +28,11 @@ public class EntPayServiceImplTest { @Inject private WxPayService payService; + /** + * Test ent pay. + * + * @throws WxPayException the wx pay exception + */ @Test public void testEntPay() throws WxPayException { EntPayRequest request = EntPayRequest.newBuilder() @@ -42,16 +47,31 @@ public class EntPayServiceImplTest { this.logger.info(this.payService.getEntPayService().entPay(request).toString()); } + /** + * Test query ent pay. + * + * @throws WxPayException the wx pay exception + */ @Test public void testQueryEntPay() throws WxPayException { this.logger.info(this.payService.getEntPayService().queryEntPay("11212121").toString()); } + /** + * Test get public key. + * + * @throws Exception the exception + */ @Test public void testGetPublicKey() throws Exception { this.logger.info(this.payService.getEntPayService().getPublicKey()); } + /** + * Test pay bank. + * + * @throws Exception the exception + */ @Test public void testPayBank() throws Exception { EntPayBankResult result = this.payService.getEntPayService().payBank(EntPayBankRequest.builder() @@ -65,6 +85,11 @@ public class EntPayServiceImplTest { this.logger.info(result.toString()); } + /** + * Test query pay bank. + * + * @throws Exception the exception + */ @Test public void testQueryPayBank() throws Exception { this.logger.info(this.payService.getEntPayService().queryPayBank("123").toString()); diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/ApiTestModule.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/ApiTestModule.java index 008d7d8b..d46c98c4 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/ApiTestModule.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/ApiTestModule.java @@ -14,6 +14,9 @@ import com.google.inject.Module; import com.thoughtworks.xstream.XStream; import me.chanjar.weixin.common.util.xml.XStreamInitializer; +/** + * The type Api test module. + */ public class ApiTestModule implements Module { private final Logger log = LoggerFactory.getLogger(this.getClass()); private static final String TEST_CONFIG_XML = "test-config.xml"; diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/XmlWxPayConfig.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/XmlWxPayConfig.java index ca7d7cf9..bdb394cd 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/XmlWxPayConfig.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/XmlWxPayConfig.java @@ -3,14 +3,27 @@ package com.github.binarywang.wxpay.testbase; import com.github.binarywang.wxpay.config.WxPayConfig; import com.thoughtworks.xstream.annotations.XStreamAlias; +/** + * The type Xml wx pay config. + */ @XStreamAlias("xml") public class XmlWxPayConfig extends WxPayConfig { private String openid; + /** + * Gets openid. + * + * @return the openid + */ public String getOpenid() { return openid; } + /** + * Sets openid. + * + * @param openid the openid + */ public void setOpenid(String openid) { this.openid = openid; } diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/util/SignUtilsTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/util/SignUtilsTest.java index 57c185b5..9247d852 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/util/SignUtilsTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/util/SignUtilsTest.java @@ -1,10 +1,11 @@ package com.github.binarywang.wxpay.util; +import org.testng.annotations.*; + import com.google.common.base.Splitter; -import org.testng.annotations.Test; import static com.github.binarywang.wxpay.constant.WxPayConstants.SignType.HMAC_SHA256; -import static org.testng.Assert.assertEquals; +import static org.testng.Assert.*; /** *
@@ -16,23 +17,38 @@ import static org.testng.Assert.assertEquals;
  * @author Binary Wang
  */
 public class SignUtilsTest {
+  /**
+   * Test create sign.
+   *
+   * @throws Exception the exception
+   */
   @Test
   public void testCreateSign() throws Exception {
     String signKey = "192006250b4c09247ec02edce69f6a2d";
     String message = "appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA";
-    assertEquals(SignUtils.createSign((Splitter.on("&").withKeyValueSeparator("=").split(message)), null, signKey, false),
+    assertEquals(SignUtils.createSign((Splitter.on("&").withKeyValueSeparator("=").split(message)), null, signKey, null),
       "9A0A8659F005D6984697E2CA0A9CF3B7");
   }
 
+  /**
+   * Test create sign hmacsha 256.
+   *
+   * @throws Exception the exception
+   */
   @Test
   public void testCreateSign_HMACSHA256() throws Exception {
     String signKey = "192006250b4c09247ec02edce69f6a2d";
     final String message = "appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA";
     String sign = SignUtils.createSign(Splitter.on("&").withKeyValueSeparator("=").split(message),
-      HMAC_SHA256, signKey, false);
+      HMAC_SHA256, signKey, null);
     assertEquals(sign, "6A9AE1657590FD6257D693A078E1C3E4BB6BA4DC30B23E0EE2496E54170DACD6");
   }
 
+  /**
+   * Test check sign.
+   *
+   * @throws Exception the exception
+   */
   @Test
   public void testCheckSign() throws Exception {
   }